Browse Source

Add ReFine plugin

tags/2018-04-16
falkTX 7 years ago
parent
commit
6842a43ea2
51 changed files with 12947 additions and 0 deletions
  1. +11
    -0
      ports/refine/LV2/premake.lua
  2. +11
    -0
      ports/refine/VST/premake.lua
  3. +251
    -0
      ports/refine/source/Analyzer.cpp
  4. +73
    -0
      ports/refine/source/Analyzer.h
  5. +7324
    -0
      ports/refine/source/BinaryData.cpp
  6. +31
    -0
      ports/refine/source/BinaryData.h
  7. +143
    -0
      ports/refine/source/Buffers.cpp
  8. +136
    -0
      ports/refine/source/Buffers.h
  9. +28
    -0
      ports/refine/source/JuceHeader.h
  10. +60
    -0
      ports/refine/source/JucePluginCharacteristics.h
  11. +156
    -0
      ports/refine/source/MiscDsp.cpp
  12. +82
    -0
      ports/refine/source/MiscDsp.h
  13. +70
    -0
      ports/refine/source/PluginEditor.cpp
  14. +38
    -0
      ports/refine/source/PluginEditor.h
  15. +126
    -0
      ports/refine/source/PluginProcessor.cpp
  16. +48
    -0
      ports/refine/source/PluginProcessor.h
  17. +19
    -0
      ports/refine/source/ReFineLookAndFeel.cpp
  18. +86
    -0
      ports/refine/source/ReFineLookAndFeel.h
  19. +298
    -0
      ports/refine/source/RefineDsp.cpp
  20. +185
    -0
      ports/refine/source/RefineDsp.h
  21. BIN
      ports/refine/source/Ressources/background.png
  22. BIN
      ports/refine/source/Ressources/blue.png
  23. BIN
      ports/refine/source/Ressources/green.png
  24. BIN
      ports/refine/source/Ressources/red.png
  25. BIN
      ports/refine/source/Ressources/vu_blue.png
  26. BIN
      ports/refine/source/Ressources/vu_green.png
  27. BIN
      ports/refine/source/Ressources/vu_red.png
  28. BIN
      ports/refine/source/Ressources/x2button.png
  29. +127
    -0
      ports/refine/source/Visualisation.cpp
  30. +31
    -0
      ports/refine/source/Visualisation.h
  31. +98
    -0
      ports/refine/source/ffft/Array.h
  32. +99
    -0
      ports/refine/source/ffft/Array.hpp
  33. +101
    -0
      ports/refine/source/ffft/DynArray.h
  34. +144
    -0
      ports/refine/source/ffft/DynArray.hpp
  35. +146
    -0
      ports/refine/source/ffft/FFTReal.h
  36. +934
    -0
      ports/refine/source/ffft/FFTReal.hpp
  37. +131
    -0
      ports/refine/source/ffft/FFTRealFixLen.h
  38. +323
    -0
      ports/refine/source/ffft/FFTRealFixLen.hpp
  39. +90
    -0
      ports/refine/source/ffft/FFTRealFixLenParam.h
  40. +96
    -0
      ports/refine/source/ffft/FFTRealPassDirect.h
  41. +205
    -0
      ports/refine/source/ffft/FFTRealPassDirect.hpp
  42. +101
    -0
      ports/refine/source/ffft/FFTRealPassInverse.h
  43. +230
    -0
      ports/refine/source/ffft/FFTRealPassInverse.hpp
  44. +78
    -0
      ports/refine/source/ffft/FFTRealSelect.h
  45. +63
    -0
      ports/refine/source/ffft/FFTRealSelect.hpp
  46. +99
    -0
      ports/refine/source/ffft/FFTRealUseTrigo.h
  47. +92
    -0
      ports/refine/source/ffft/FFTRealUseTrigo.hpp
  48. +107
    -0
      ports/refine/source/ffft/OscSinCos.h
  49. +123
    -0
      ports/refine/source/ffft/OscSinCos.hpp
  50. +60
    -0
      ports/refine/source/ffft/def.h
  51. +293
    -0
      ports/refine/source/ffft/readme.txt

+ 11
- 0
ports/refine/LV2/premake.lua View File

@@ -0,0 +1,11 @@
dofile("../../../scripts/make-project.lua")
package = make_juce_lv2_project("ReFine")
package.files = {
matchfiles (
"../source/*.cpp",
"../../../libs/juce-plugin/JucePluginMain.cpp"
)
}

+ 11
- 0
ports/refine/VST/premake.lua View File

@@ -0,0 +1,11 @@
dofile("../../../scripts/make-project.lua")
package = make_juce_vst_project("ReFine")
package.files = {
matchfiles (
"../source/*.cpp",
"../../../libs/juce-plugin/JucePluginMain.cpp"
)
}

+ 251
- 0
ports/refine/source/Analyzer.cpp View File

@@ -0,0 +1,251 @@
#include "Analyzer.h"


struct Analyzer::Data
{
Data(int size_);
void clear();
void copyFrom (const Data& other);
const juce::CriticalSection& getLock() const;

const int size;
juce::HeapBlock<float> mags;
juce::HeapBlock<float> angles;

private:

juce::CriticalSection lock;
JUCE_DECLARE_NON_COPYABLE(Data)
};

Analyzer::Data::Data (int size_)
: size (size_),
mags (size),
angles (size)
{
clear();
}

void Analyzer::Data::clear()
{
juce::zeromem(mags, sizeof(float) * size);
juce::zeromem(angles, sizeof(float) * size);
}

void Analyzer::Data::copyFrom (const Data& other)
{
if (other.size == size)
{
memcpy(mags, other.mags, sizeof(float) * size);
memcpy(angles, other.angles, sizeof(float) * size);
}
}

const juce::CriticalSection& Analyzer::Data::getLock() const
{
return lock;
}


RmsEnvelope::RmsEnvelope (int envsize, double rmsLength, double updatetime)
: rms (rmsLength), rmsVals (envsize+1), updateTime (updatetime), sampleRate (44100)
{
clear();
}

void RmsEnvelope::setSampleRate (double newSampleRate)
{
sampleRate = newSampleRate;
rms.setSampleRate(sampleRate);
clear();
}

void RmsEnvelope::clear()
{
rms.clear();
rmsVals.clear();
updateIndex = 0;
}

bool RmsEnvelope::process (const float inL, const float inR)
{
rms.process(inL, inR);

const int ovSize = int(updateTime * sampleRate);
jassert(ovSize > 100);

if (++updateIndex >= ovSize)
{
updateIndex = 0;
const float rmsVal = rms.getRms();

rmsVals.push(rmsVal);
return true;
}

return false;
}

void RmsEnvelope::processBlock (const float* inL, const float* inR, int numSamples)
{
ScopedLock lock(processLock);

const int ovSize = int(updateTime * sampleRate);

jassert(ovSize > 100);

int idx = 0;

while (numSamples > 0)
{
const int curNumSamples = jmin(ovSize-updateIndex, numSamples);

rms.processBlock(&inL[idx], &inR[idx], curNumSamples);
numSamples -= curNumSamples;
idx += curNumSamples;
updateIndex += curNumSamples;

if (updateIndex >= ovSize)
{
updateIndex = 0;
const float rmsVal = rms.getRms();

rmsVals.push(rmsVal);
}
}
}

bool RmsEnvelope::getData (Array<float>& data) const
{
const int dataLength = getDataLength();

if (data.size() < dataLength)
{
ScopedTryLock lock(processLock);

if (! lock.isLocked())
return false;

for (int i=0; i<data.size(); ++i)
data.getReference(i) = rmsVals[i];

return true;
}

return false;
}

int RmsEnvelope::getDataLength() const
{
return rmsVals.getSize() - 1;
}

Analyzer::Analyzer()
: sampleRate (0)
{
setSampleRate(44100);
}

void Analyzer::clear()
{
fftIndex = 0;
data->clear();
}

void Analyzer::processBlock (const float* inL, const float* inR, int numSamples)
{
for (int i=0; i<numSamples; ++i)
{
x[fftIndex] = 0.5f * (inL[i] + inR[i]) * window[fftIndex];
++fftIndex;

if (fftIndex >= fftBlockSize)
{
processFFT();
fftIndex = 0;
}
}
}

int Analyzer::getFFTSize() const
{
return fftBlockSize;
}

int Analyzer::getNumBins() const
{
return numBins;
}

bool Analyzer::getData (Data& d) const
{
ScopedTryLock lock(data->getLock());

if (lock.isLocked())
{
d.copyFrom(*data);
return true;
}

return false;
}

void Analyzer::setSampleRate (double newSampleRate)
{
if (sampleRate != newSampleRate)
{
sampleRate = newSampleRate;

fftBlockSize = 512 * jmax(1, int(sampleRate / 44100));
numBins = fftBlockSize / 2 + 1;

fft = new ffft::FFTReal<float> (fftBlockSize);
x.realloc(fftBlockSize);
f.realloc(fftBlockSize);
window.realloc(fftBlockSize);
data = new Data(numBins);

{
const float alpha = 0.16f;
const float a0 = 0.5f * (1-alpha);
const float a1 = 0.5f;
const float a2 = alpha*0.5f;

for (int i=0; i<fftBlockSize; ++i)
window[i] = a0 - a1*cos(2*float_Pi*i/(fftBlockSize-1)) + a2*cos(4*float_Pi*i/(fftBlockSize-1));
}

clear();
}
}

double Analyzer::getSampleRate() const
{
return sampleRate;
}

void Analyzer::processFFT()
{
fft->do_fft(f, x);

const int imagOffset = fftBlockSize / 2;
const float weight = 1.f / fftBlockSize;

{
ScopedLock lock(data->getLock());

data->mags[0] = f[0]*f[0] * weight;
data->mags[imagOffset] = f[imagOffset]*f[imagOffset] * weight;
data->angles[0] = 0;
data->angles[numBins-1] = 0;

for (int i=1; i<numBins-1; ++i)
{
const float re = f[i];
const float im = f[imagOffset + i];
data->mags[i] = (re*re + im*im) * weight;
data->angles[i] = atan2(im, re);
}
}
}

+ 73
- 0
ports/refine/source/Analyzer.h View File

@@ -0,0 +1,73 @@
#ifndef __ANALYZER_H__
#define __ANALYZER_H__

#include "JuceHeader.h"
#include "Buffers.h"
#include "ffft/FFTReal.h"

class RmsEnvelope
{
public:
RmsEnvelope (int envsize, double rmsLength, double updatetime);
void setSampleRate (double newSampleRate);
void clear();

bool process (const float inL, const float inR);
void processBlock (const float* inL, const float* inR, int numSamples);

bool getData (Array<float>& data) const;
int getDataLength() const;

private:

RmsLevel rms;
CircularBuffer<float> rmsVals;
double updateTime;
double sampleRate;
int updateIndex;

juce::CriticalSection processLock;

JUCE_DECLARE_NON_COPYABLE (RmsEnvelope)
};


class Analyzer
{
public:

struct Data;

Analyzer();

void clear();
void processBlock (const float* inL, const float* inR, int numSamples);

int getFFTSize() const;
int getNumBins() const;
bool getData(Data& d) const;

void setSampleRate (double newSampleRate);
double getSampleRate() const;

private:

void processFFT();

juce::ScopedPointer<ffft::FFTReal<float> > fft;
juce::HeapBlock<float> x;
juce::HeapBlock<float> f;
juce::HeapBlock<float> window;
juce::ScopedPointer<Data> data;

int fftIndex;

int fftBlockSize;
int numBins;

double sampleRate;
};


#endif // __ANALYZER_H__

+ 7324
- 0
ports/refine/source/BinaryData.cpp
File diff suppressed because it is too large
View File


+ 31
- 0
ports/refine/source/BinaryData.h View File

@@ -0,0 +1,31 @@
/* (Auto-generated binary data file). */
#pragma once
namespace BinaryData
{
extern const char* background_png;
const int background_pngSize = 49833;
extern const char* blue_png;
const int blue_pngSize = 66845;
extern const char* green_png;
const int green_pngSize = 66938;
extern const char* red_png;
const int red_pngSize = 66547;
extern const char* vu_blue_png;
const int vu_blue_pngSize = 13293;
extern const char* vu_green_png;
const int vu_green_pngSize = 13138;
extern const char* vu_red_png;
const int vu_red_pngSize = 13086;
extern const char* x2button_png;
const int x2button_pngSize = 2312;
}

+ 143
- 0
ports/refine/source/Buffers.cpp View File

@@ -0,0 +1,143 @@
#include "Buffers.h"

RmsBuffer::RmsBuffer (int initSize)
: buffer (initSize)
{
clear();
}

void RmsBuffer::clear()
{
rms = 0;
buffer.clear();
}

double RmsBuffer::process (double in)
{
const double x = in * in;
const double tmp = buffer.pushAndGet(x);
rms = rms + x - tmp;

return rms / buffer.getSize();
}

void RmsBuffer::processBlock (const double* in, int numSamples)
{
for (int i = 0; i<numSamples; ++i)
process(in[i]);
}

void RmsBuffer::setSize (int newSize)
{
if (buffer.setSize(newSize))
rms = 0;
}

int RmsBuffer::getSize()
{
return buffer.getSize();
}

double RmsBuffer::getRms()
{
return rms / buffer.getSize();
}

RmsLevel::RmsLevel (double lengthMs)
: ms (lengthMs), size (0), index (0)
{
setSampleRate(44100);
}

void RmsLevel::setSampleRate (double sampleRate)
{
const int newSize = int(sampleRate*ms*0.001);

if (size != newSize)
{
size = newSize;
data.realloc(size);
}
clear();
}

void RmsLevel::clear()
{
zeromem(data, sizeof(double) * size);
rms = 0;
index = 0;
}

void RmsLevel::process (float in)
{
const double x = in*in;
rms += x - data[index];

if (rms < 1e-8)
rms = 0;

data[index] = x;

if (++index >= size)
index = 0;
}

void RmsLevel::process (float inL, float inR)
{
const double x = 0.5f * (inL*inL + inR*inR);
rms += x - data[index];

if (rms < 1e-8)
rms = 0;

data[index] = x;

if (++index >= size)
index = 0;
}

void RmsLevel::processBlock (const float* inL, const float* inR, int numSamples)
{
if (inR == nullptr)
{
for (int i = 0; i<numSamples; ++i)
{
const double x = inL[i] * inL[i];
rms += x - data[index];

if (rms < 1e-8)
rms = 0;

data[index] = x;

if (++index >= size)
index = 0;
}
}
else
{
for (int i = 0; i<numSamples; ++i)
{
const double x = 0.5f * (inL[i] * inL[i] + inR[i] * inR[i]);
rms += x - data[index];

if (rms < 1e-8)
rms = 0;

data[index] = x;

if (++index >= size)
index = 0;
}
}
}

float RmsLevel::getRms()
{
return sqrt(float(rms / size));
}

double RmsLevel::getRmsLength()
{
return ms;
}

+ 136
- 0
ports/refine/source/Buffers.h View File

@@ -0,0 +1,136 @@
#ifndef BUFFERS_H_INCLUDED
#define BUFFERS_H_INCLUDED

#include "JuceHeader.h"

template <class DataType>
class CircularBuffer
{
public:
CircularBuffer (int initSize)
: size (0), index (0)
{
setSize(initSize);
clear();
}

bool setSize (int newSize)
{
jassert(newSize > 0);

if (size != newSize && newSize > 0)
{
size = newSize;
data.realloc(size);
clear();

return true;
}

return false;
}

int getSize() const
{
return size;
}

void clear()
{
juce::zeromem(data, sizeof(DataType) * size);
index = 0;
}

void push (DataType x)
{
data[index] = x;

if (++index >= size)
index = 0;
}

DataType pushAndGet (DataType x)
{
DataType ret = data[index];
push(x);

return ret;
}

DataType operator[] (int offset) const
{
int idx = index - offset - 1;

if (idx < 0)
idx += size;

jassert(idx >= 0 && idx < size);
return data[idx];
}

void processBlock (DataType* proc, int numSamples)
{
for (int i = 0; i<numSamples; ++i)
proc[i] = pushAndGet(proc[i]);
}

private:

int size;
juce::HeapBlock<DataType> data;
int index;
};

class RmsBuffer
{
public:
RmsBuffer (int initSize);

void clear();

double process (double in);

void processBlock (const double* in, int numSamples);

void setSize (int newSize);

int getSize();

double getRms();


private:

double rms;
CircularBuffer<double> buffer;
};


class RmsLevel
{
public:
RmsLevel (double lengthMs);
void setSampleRate (double sampleRate);

void clear();
void process (float in);
void process (float inL, float inR);
void processBlock (const float* inL, const float* inR, int numSamples);
float getRms();
double getRmsLength();


private:

const double ms;
int size;
HeapBlock<double> data;
double rms;

int index;

JUCE_DECLARE_NON_COPYABLE(RmsLevel)
};


#endif // BUFFERS_H_INCLUDED

+ 28
- 0
ports/refine/source/JuceHeader.h View File

@@ -0,0 +1,28 @@
/*
IMPORTANT! This file is auto-generated each time you save your
project - if you alter its contents, your changes may be overwritten!
This is the header file that your files should include in order to get all the
JUCE library headers. You should avoid including the JUCE headers directly in
your own source files, because that wouldn't pick up the correct configuration
options for your app.
*/
#ifndef __APPHEADERFILE_JH7QDM__
#define __APPHEADERFILE_JH7QDM__
#include "JucePluginMain.h"
#include "BinaryData.h"
using namespace juce;
namespace ProjectInfo
{
const char* const projectName = "ReFine";
const char* const versionString = "1.1.0";
const int versionNumber = 0x10100;
}
#endif // __APPHEADERFILE_JH7QDM__

+ 60
- 0
ports/refine/source/JucePluginCharacteristics.h View File

@@ -0,0 +1,60 @@
/*
IMPORTANT! This file is auto-generated by the Jucer each time you save your
project - if you alter its contents, your changes may be overwritten!
This header file contains configuration options for the plug-in. If you need to change any of
these, it'd be wise to do so using the Jucer, rather than editing this file directly...
*/
#ifndef __PLUGINCHARACTERISTICS_D4EFFF1A__
#define __PLUGINCHARACTERISTICS_D4EFFF1A__
#define JucePlugin_Name "ReFine"
#define JucePlugin_Desc "ReFine"
#define JucePlugin_Manufacturer "Lkjb"
#define JucePlugin_ManufacturerCode 'Lkjb'
#define JucePlugin_PluginCode 'LkRf'
#define JucePlugin_MaxNumInputChannels 2
#define JucePlugin_MaxNumOutputChannels 2
#define JucePlugin_PreferredChannelConfigurations {2, 2}, {1, 1}
#define JucePlugin_IsSynth 0
#define JucePlugin_IsMidiEffect 0
#define JucePlugin_WantsMidiInput 0
#define JucePlugin_ProducesMidiOutput 0
#define JucePlugin_SilenceInProducesSilenceOut 0
#define JucePlugin_TailLengthSeconds 0
#define JucePlugin_EditorRequiresKeyboardFocus 1
#define JucePlugin_Version 1.1.0
#define JucePlugin_VersionCode 0x10100
#define JucePlugin_VersionString "1.1.0"
#define JucePlugin_VSTUniqueID JucePlugin_PluginCode
#define JucePlugin_VSTCategory kPlugCategEffect
#define JucePlugin_AUMainType kAudioUnitType_Effect
#define JucePlugin_AUSubType JucePlugin_PluginCode
#define JucePlugin_AUExportPrefix ReFineAU
#define JucePlugin_AUExportPrefixQuoted "ReFineAU"
#define JucePlugin_AUManufacturerCode JucePlugin_ManufacturerCode
#define JucePlugin_CFBundleIdentifier com.lkjb.ReFine
#define JucePlugin_AUCocoaViewClassName PitchedDelayAU_V1
#define JucePlugin_RTASCategory ePlugInCategory_None
#define JucePlugin_RTASManufacturerCode JucePlugin_ManufacturerCode
#define JucePlugin_RTASProductId JucePlugin_PluginCode
#define JucePlugin_RTASDisableBypass 0
#define JucePlugin_RTASDisableMultiMono 0
#define JucePlugin_AAXIdentifier com.yourcompany.ReFine
#define JucePlugin_AAXManufacturerCode JucePlugin_ManufacturerCode
#define JucePlugin_AAXProductId JucePlugin_PluginCode
#define JucePlugin_AAXPluginId JucePlugin_PluginCode
#define JucePlugin_AAXCategory AAX_ePlugInCategory_Dynamics
#define JucePlugin_AAXDisableBypass 0
#define JucePlugin_LV2URI "https://github.com/lkjbdsp/lkjb-plugins#ReFine"
//#define JucePlugin_LV2Category "DelayPlugin"
#define JucePlugin_WantsLV2Latency 0
#define JucePlugin_WantsLV2State 0
#define JucePlugin_WantsLV2TimePos 0
#define JucePlugin_WantsLV2Presets 0
#endif // __PLUGINCHARACTERISTICS_D4EFFF1A__

+ 156
- 0
ports/refine/source/MiscDsp.cpp View File

@@ -0,0 +1,156 @@
#include "MiscDsp.h"

BiquadCoefficients::BiquadCoefficients() : b0 (1), b1 (0), b2 (0), a1 (0), a2 (0) {}

void BiquadCoefficients::create (BiquadType::BiquadType type, double freq, double Q, double sampleRate)
{
const double w0 = 2 * juce::double_Pi * freq / sampleRate;
const double cosw0 = cos(w0);
const double alpha = sin(w0) / (2 * Q);

double a0 = 1;

switch (type)
{
case BiquadType::kBypass:
b0 = 1; b1 = 0; b2 = 0; a1 = 0; a2 = 0;
break;
case BiquadType::kHighPass6:
a1 = (tan(w0 / 2) - 1) / (tan(w0 / 2) + 1);
b0 = (1 - a1) * 0.5;
b1 = (a1 - 1) * 0.5;
b2 = 0;
a2 = 0;
break;
case BiquadType::kLowPass:
a0 = 1 + alpha;
b0 = (1 - cosw0) / 2;
b1 = 1 - cosw0;
b2 = (1 - cosw0) / 2;
a1 = -2 * cosw0;
a2 = 1 - alpha;
break;
case BiquadType::kBandPass:
a0 = 1 + alpha;
b0 = alpha;
b1 = 0;
b2 = -alpha;
a1 = -2 * cosw0;
a2 = 1 - alpha;
break;
default:
jassertfalse;
break;
}

b0 /= a0;
b1 /= a0;
b2 /= a0;
a1 /= a0;
a2 /= a0;
}


StaticBiquad::StaticBiquad()
: sampleRate (44100)
{
setFilter(BiquadType::kBypass, 1000, 0.7);
clear();
}

void StaticBiquad::clear()
{
xl[0] = 0; xl[1] = 0;
yl[0] = 0; yl[1] = 0;
xr[0] = 0; xr[1] = 0;
yr[0] = 0; yr[1] = 0;
}

void StaticBiquad::setSampleRate (double newSampleRate)
{
sampleRate = newSampleRate;
setFilter(curType, curFreq, curQ);
}

void StaticBiquad::setFilter (BiquadType::BiquadType type, double freq, double Q)
{
curType = type;
curFreq = freq;
curQ = Q;

coeff.create(curType, curFreq, curQ, sampleRate);
}

float StaticBiquad::process (float in)
{
const double x = (double) in;
double y = x*coeff.b0 + xl[0] * coeff.b1 + xl[1] * coeff.b2 - yl[0] * coeff.a1 - yl[1] * coeff.a2;

if (y > -1e-8 && y < 1e-8)
y = 0;

xl[1] = xl[0]; xl[0] = x;
yl[1] = yl[0]; yl[0] = y;

return (float) y;
}

void StaticBiquad::processBlock (float* in, int numSamples)
{
for (int i = 0; i<numSamples; ++i)
in[i] = process(in[i]);
}

void StaticBiquad::processBlock (float* inL, float* inR, int numSamples)
{
for (int i = 0; i<numSamples; ++i)
{
const double xL = (double) inL[i];
const double xR = (double) inR[i];
double yL = xL*coeff.b0 + xl[0] * coeff.b1 + xl[1] * coeff.b2 - yl[0] * coeff.a1 - yl[1] * coeff.a2;
double yR = xR*coeff.b0 + xr[0] * coeff.b1 + xr[1] * coeff.b2 - yr[0] * coeff.a1 - yr[1] * coeff.a2;

if (yL > -1e-8 && yL < 1e-8)
yL = 0;

if (yR > -1e-8 && yR < 1e-8)
yR = 0;

xl[1] = xl[0]; xl[0] = xL;
xr[1] = xr[0]; xr[0] = xR;
yl[1] = yl[0]; yl[0] = yL;
yr[1] = yr[0]; yr[0] = yR;

inL[i] = (float) yL;
inR[i] = (float) yR;
}
}

float StaticBiquad::getLast (bool left)
{
return float(left ? yl[0] : yr[0]);
}

SimpleNoiseGen::SimpleNoiseGen(float levelDb)
: level (pow(10.f, 0.05f * levelDb))
{
}

void SimpleNoiseGen::processBlock (float* chL, float* chR, int numSamples)
{
for (int i = 0; i<numSamples; ++i)
{
const float noise = (rnd.nextFloat() - 0.5f) * 2.f * level;
chL[i] += noise;
chR[i] += noise;
}
}

void SimpleNoiseGen::processBlock (float* ch, int numSamples)
{
for (int i = 0; i<numSamples; ++i)
{
const float noise = (rnd.nextFloat() - 0.5f) * 2.f * level;
ch[i] += noise;
}
}

+ 82
- 0
ports/refine/source/MiscDsp.h View File

@@ -0,0 +1,82 @@
#ifndef DSPSTUFF_H_INCLUDED
#define DSPSTUFF_H_INCLUDED

#include "JuceHeader.h"

namespace BiquadType
{
enum BiquadType
{
kBypass,
kHighPass6,
kLowPass,
kBandPass,

kNumFilters
};
}

struct BiquadCoefficients
{
BiquadCoefficients();

void create (BiquadType::BiquadType type, double freq, double Q, double sampleRate);

double b0;
double b1;
double b2;
double a1;
double a2;
};

class StaticBiquad
{
public:

StaticBiquad();

void clear();

void setSampleRate (double newSampleRate);

void setFilter (BiquadType::BiquadType type, double freq, double Q);

float process (float in);

void processBlock (float* in, int numSamples);

void processBlock (float* inL, float* inR, int numSamples);

float getLast (bool left);

private:

double sampleRate;

BiquadType::BiquadType curType;
double curFreq;
double curQ;

BiquadCoefficients coeff;

double xl[2];
double yl[2];
double xr[2];
double yr[2];
};

class SimpleNoiseGen
{
public:

SimpleNoiseGen (float levelDb);
void processBlock (float* chL, float* chR, int numSamples);
void processBlock (float* ch, int numSamples);

private:
float level;
juce::Random rnd;
};


#endif // DSPSTUFF_H_INCLUDED

+ 70
- 0
ports/refine/source/PluginEditor.cpp View File

@@ -0,0 +1,70 @@
#include "PluginProcessor.h"
#include "PluginEditor.h"


//==============================================================================
ReFinedAudioProcessorEditor::ReFinedAudioProcessorEditor (ReFinedAudioProcessor& p)
: AudioProcessorEditor (&p), processor (p),
background (ImageCache::getFromMemory(BinaryData::background_png, BinaryData::background_pngSize)),
redSlider (ImageCache::getFromMemory(BinaryData::red_png, BinaryData::red_pngSize), ImageCache::getFromMemory(BinaryData::vu_red_png, BinaryData::vu_red_pngSize), *p.parameters, "red"),
greenSlider (ImageCache::getFromMemory(BinaryData::green_png, BinaryData::green_pngSize), ImageCache::getFromMemory (BinaryData::vu_green_png, BinaryData::vu_green_pngSize), *p.parameters, "green"),
blueSlider (ImageCache::getFromMemory(BinaryData::blue_png, BinaryData::blue_pngSize), ImageCache::getFromMemory(BinaryData::vu_blue_png, BinaryData::vu_blue_pngSize), *p.parameters, "blue"),
x2Button (*p.parameters, "x2"),
visualisation (p.getDsp())
{
setLookAndFeel(refinedLookAndFeel);

addAndMakeVisible(redSlider);
addAndMakeVisible(greenSlider);
addAndMakeVisible(blueSlider);
addAndMakeVisible(x2Button);

addAndMakeVisible(visualisation);

setSize (450, 300);
startTimer(100);
}

ReFinedAudioProcessorEditor::~ReFinedAudioProcessorEditor()
{
}

//==============================================================================
void ReFinedAudioProcessorEditor::paint (Graphics& g)
{
g.setColour(Colours::black);
g.drawImageAt(background, 0, 0);

}

void ReFinedAudioProcessorEditor::resized()
{
const int sliderWidth = 64;
const int sliderHeight = 64;
const int ySlider = 221;
const int yButton = 7;
const int xRed = 65;
const int xGreen = 193;
const int xBlue = 321;
const int xButton = 209;
const int buttonWidth = 32;
const int buttonHeight = 16;

redSlider.setBounds(xRed, ySlider, sliderWidth, sliderHeight);
greenSlider.setBounds(xGreen, ySlider, sliderWidth, sliderHeight);
blueSlider.setBounds(xBlue, ySlider, sliderWidth, sliderHeight);
x2Button.setBounds(xButton, yButton, buttonWidth, buttonHeight);
visualisation.setBounds(31, 35, 388, 150);
}

void ReFinedAudioProcessorEditor::timerCallback()
{
const RefineDsp& dsp(processor.getDsp());
const float transient = dsp.getTransient();
const float nonTransient = dsp.getNonTransient();
const float level = dsp.getLevel();

redSlider.setVuValue(nonTransient);
greenSlider.setVuValue(level);
blueSlider.setVuValue(transient);
}

+ 38
- 0
ports/refine/source/PluginEditor.h View File

@@ -0,0 +1,38 @@
#ifndef PLUGINEDITOR_H_INCLUDED
#define PLUGINEDITOR_H_INCLUDED

#include "JuceHeader.h"
#include "PluginProcessor.h"
#include "ReFineLookAndFeel.h"
#include "Visualisation.h"

class ReFinedAudioProcessorEditor : public AudioProcessorEditor, public Timer
{
public:
ReFinedAudioProcessorEditor (ReFinedAudioProcessor&);
~ReFinedAudioProcessorEditor();

void paint (Graphics&) override;
void resized() override;

void timerCallback() override;

private:

ReFinedAudioProcessor& processor;

Image background;

RefinedSlider redSlider;
RefinedSlider greenSlider;
RefinedSlider blueSlider;
X2Button x2Button;

Visualisation visualisation;

SharedResourcePointer<RefineLookAndFeel> refinedLookAndFeel;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ReFinedAudioProcessorEditor)
};


#endif // PLUGINEDITOR_H_INCLUDED

+ 126
- 0
ports/refine/source/PluginProcessor.cpp View File

@@ -0,0 +1,126 @@
#include "PluginProcessor.h"
#include "PluginEditor.h"
#include "xmmintrin.h"

ReFinedAudioProcessor::ReFinedAudioProcessor()
{
parameters = new AudioProcessorValueTreeState(*this, nullptr);
parameters->createAndAddParameter("red", "red", "", NormalisableRange<float>(0.f, 1.f), 0.f, [](float val) { return String(val, 2); }, [](const String& s) { return (float) s.getDoubleValue(); });
parameters->createAndAddParameter("green", "green", "", NormalisableRange<float>(0.f, 1.f), 0.f, [](float val) { return String(val, 2); }, [](const String& s) { return (float) s.getDoubleValue(); });
parameters->createAndAddParameter("blue", "blue", "", NormalisableRange<float>(0.f, 1.f), 0.f, [](float val) { return String(val, 2); }, [](const String& s) { return (float) s.getDoubleValue(); });
parameters->createAndAddParameter("x2", "x2", "", NormalisableRange<float>(0.f, 1.f), 0.f, [](float val) { return val < 0.5f ? "Off" : "On"; }, [](const String& s) { return s.trim() == "1" || s.trim().toLowerCase() == "on" ? 1.f : 0.f; });
}

ReFinedAudioProcessor::~ReFinedAudioProcessor()
{
}

const String ReFinedAudioProcessor::getName() const
{
return JucePlugin_Name;
}

bool ReFinedAudioProcessor::acceptsMidi() const
{
return false;
}

bool ReFinedAudioProcessor::producesMidi() const
{
return false;
}

double ReFinedAudioProcessor::getTailLengthSeconds() const
{
return 0.0;
}

int ReFinedAudioProcessor::getNumPrograms()
{
return 1;
}

int ReFinedAudioProcessor::getCurrentProgram()
{
return 0;
}

void ReFinedAudioProcessor::setCurrentProgram (int /*index*/)
{
}

const String ReFinedAudioProcessor::getProgramName (int /*index*/)
{
return String();
}

void ReFinedAudioProcessor::changeProgramName (int /*index*/, const String& /*newName*/)
{
}

void ReFinedAudioProcessor::prepareToPlay (double newSampleRate, int /*samplesPerBlock*/)
{
dsp.setSampleRate(newSampleRate);
}

void ReFinedAudioProcessor::releaseResources()
{
}

void ReFinedAudioProcessor::processBlock (AudioSampleBuffer& buffer, MidiBuffer& /*midiMessages*/)
{
{
const float low = parameters->getParameter("red")->getValue();
const float mid = parameters->getParameter("green")->getValue();
const float high = parameters->getParameter("blue")->getValue();
const float x2mode = parameters->getParameter("x2")->getValue();

dsp.setLow(0.9f * low + 0.05f * mid + 0.05f * high);
dsp.setMid(0.9f * mid + 0.05f * high + 0.05f * low);
dsp.setHigh(0.9f * high + 0.05f * low + 0.05f * mid);
dsp.setX2Mode(x2mode > 0.5f);
}

const int numChannels = buffer.getNumChannels();
const int numSamples = buffer.getNumSamples();
float* chL = buffer.getWritePointer(0);
float* chR = numChannels > 1 ? buffer.getWritePointer(1) : nullptr;

dsp.processBlock(chL, chR, numSamples);
}

bool ReFinedAudioProcessor::hasEditor() const
{
return true;
}

AudioProcessorEditor* ReFinedAudioProcessor::createEditor()
{
return new ReFinedAudioProcessorEditor (*this);
}

void ReFinedAudioProcessor::getStateInformation (MemoryBlock& destData)
{
XmlElement xml("REFINED");

for (int i = 0; i < getNumParameters(); ++i)
xml.setAttribute(getParameterName(i), getParameter(i));

copyXmlToBinary(xml, destData);
}

void ReFinedAudioProcessor::setStateInformation (const void* data, int sizeInBytes)
{
ScopedPointer<XmlElement> xml(getXmlFromBinary(data, sizeInBytes));

if (xml != nullptr)
{
for (int i = 0; i < getNumParameters(); ++i)
setParameterNotifyingHost(i, (float) xml->getDoubleAttribute(getParameterName(i), getParameter(i)));
}
}

AudioProcessor* JUCE_CALLTYPE createPluginFilter()
{
return new ReFinedAudioProcessor();
}

+ 48
- 0
ports/refine/source/PluginProcessor.h View File

@@ -0,0 +1,48 @@
#ifndef PLUGINPROCESSOR_H_INCLUDED
#define PLUGINPROCESSOR_H_INCLUDED

#include "JuceHeader.h"
#include "RefineDsp.h"

class ReFinedAudioProcessor : public AudioProcessor
{
public:
ReFinedAudioProcessor();
~ReFinedAudioProcessor();

void prepareToPlay (double sampleRate, int samplesPerBlock) override;
void releaseResources() override;

void processBlock (AudioSampleBuffer&, MidiBuffer&) override;

AudioProcessorEditor* createEditor() override;
bool hasEditor() const override;

//==============================================================================
const String getName() const override;

bool acceptsMidi() const override;
bool producesMidi() const override;
double getTailLengthSeconds() const override;

int getNumPrograms() override;
int getCurrentProgram() override;
void setCurrentProgram (int index) override;
const String getProgramName (int index) override;
void changeProgramName (int index, const String& newName) override;

void getStateInformation (MemoryBlock& destData) override;
void setStateInformation (const void* data, int sizeInBytes) override;

const RefineDsp& getDsp() const { return dsp; }

ScopedPointer<AudioProcessorValueTreeState> parameters;

private:

RefineDsp dsp;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ReFinedAudioProcessor)
};


#endif // PLUGINPROCESSOR_H_INCLUDED

+ 19
- 0
ports/refine/source/ReFineLookAndFeel.cpp View File

@@ -0,0 +1,19 @@
#include "ReFineLookAndFeel.h"

void RefineLookAndFeel::drawRotarySlider (Graphics& g, int x, int y, int width, int height, float sliderPosProportional, float /*rotaryStartAngle*/, float /*rotaryEndAngle*/, Slider& slider)
{
if (RefinedSlider* s = dynamic_cast<RefinedSlider*> (&slider))
{
const Image& sliderImg = s->sliderImage;
const Image& vuImg = s->vuImage;
jassert(sliderImg.getWidth() == vuImg.getWidth() && sliderImg.getHeight() == vuImg.getHeight());

const int wSubImage = sliderImg.getWidth();
const int numImages = sliderImg.getHeight() / wSubImage;
const int ySliderImage = wSubImage * jlimit(0, numImages - 1, static_cast<int> (sliderPosProportional * (numImages - 1) + 0.5f));
const int yVuImage = wSubImage * jlimit(0, numImages - 1, static_cast<int> (s->getVuValue() * (numImages - 1) + 0.5f));

g.drawImage(sliderImg, x, y, width, height, 0, ySliderImage, wSubImage, wSubImage, false);
g.drawImage(vuImg, x, y, width, height, 0, yVuImage, wSubImage, wSubImage, false);
}
}

+ 86
- 0
ports/refine/source/ReFineLookAndFeel.h View File

@@ -0,0 +1,86 @@
#ifndef REFINELOOKANDFEEL_H_INCLUDED
#define REFINELOOKANDFEEL_H_INCLUDED

#include "JuceHeader.h"

class RefinedSlider : public Slider
{
public:

RefinedSlider (Image slider, Image vu, AudioProcessorValueTreeState& state, const String& parameterID)
: sliderImage (slider), vuImage (vu), vuValue (0.f)
{
attachment = new AudioProcessorValueTreeState::SliderAttachment(state, parameterID, *this);
setSliderStyle(Slider::RotaryVerticalDrag);
setTextBoxStyle(Slider::NoTextBox, true, 0, 0);
}

virtual ~RefinedSlider()
{
}
void setVuValue (float newValue)
{
if (newValue != vuValue)
{
vuValue = newValue;
repaint();
}
}

float getVuValue() const
{
return vuValue;
}

const Image sliderImage;
const Image vuImage;

private:

ScopedPointer<AudioProcessorValueTreeState::SliderAttachment> attachment;
float vuValue;
JUCE_DECLARE_NON_COPYABLE(RefinedSlider)
};

class X2Button : public Button
{
public:

X2Button (AudioProcessorValueTreeState& state, const String& parameterID)
: Button ("X2Button"),
image (ImageCache::getFromMemory(BinaryData::x2button_png, BinaryData::x2button_pngSize))
{
attachment = new AudioProcessorValueTreeState::ButtonAttachment(state, parameterID, *this);
setClickingTogglesState(true);
}

void paintButton (Graphics& g, bool /*isMouseOverButton*/, bool isButtonDown)
{
const bool state = getToggleState() || isButtonDown;
const int iw = image.getWidth();
const int ih = image.getHeight();
g.drawImageAt(image.getClippedImage(juce::Rectangle<int> (0, state ? ih/2 : 0, iw, ih/2)), 0, 0);
}

private:

ScopedPointer<AudioProcessorValueTreeState::ButtonAttachment> attachment;
Image image;
};

class RefineLookAndFeel : public LookAndFeel_V3
{
public:

void drawRotarySlider (Graphics&, int x, int y, int width, int height,
float sliderPosProportional, float rotaryStartAngle, float rotaryEndAngle,
Slider&) override;

private:

};



#endif // REFINELOOKANDFEEL_H_INCLUDED

+ 298
- 0
ports/refine/source/RefineDsp.cpp View File

@@ -0,0 +1,298 @@
#include "RefineDsp.h"

RefineDsp::RefineDsp()
: sampleRate (0),
gainLow (0.f),
gainMid (0.f),
gainHigh (0.f),
noise (-140.f),
auxSize (4096),
auxLowL (auxSize),
auxHighL (auxSize),
auxLowR (auxSize),
auxHighR (auxSize),
rms300 (static_cast<int> (44100*0.3)),
rms5 (static_cast<int> (44100*0.005)),
rms (400, 100, 0.025),
colors (1),
delayL (512),
delayR (512)
{
setSampleRate(44100);
clear();
}

void RefineDsp::clear()
{
lowL.clear();
lowR.clear();
highL.clear();
highR.clear();
levelSlow.clear();
levelMid.clear();
levelFast.clear();
levelHold.clear();

rms300.clear();
rms5.clear();
transient = 0;
nonTransient = 0;
level = 0;
}

void RefineDsp::setBlockSize (int newBlockSize)
{
if (newBlockSize > auxSize)
{
auxSize = newBlockSize;
auxLowL.realloc(auxSize);
auxLowR.realloc(auxSize);
auxHighL.realloc(auxSize);
auxHighR.realloc(auxSize);
}
}

void RefineDsp::setSampleRate (double newSampleRate)
{
if (newSampleRate != sampleRate)
{
sampleRate = newSampleRate;

rms.setSampleRate(sampleRate);
colors.setSize(rms.getDataLength()+1);

lowL.setFilter(BiquadType::kBandPass, 80.f, 0.5f);
lowR.setFilter(BiquadType::kBandPass, 80.f, 0.5f);

highL.setFilter(BiquadType::kHighPass6, 10e3f, 0.5f);
highR.setFilter(BiquadType::kHighPass6, 10e3f, 0.5f);

levelSlow.setFilter(BiquadType::kLowPass, 10, sqrt(0.5));
levelMid.setFilter(BiquadType::kLowPass, 50, sqrt(0.5));
levelFast.setFilter(BiquadType::kLowPass, 200, sqrt(0.5));

rms300.setSize(int(0.3*sampleRate));
rms5.setSize(int(0.02*sampleRate));
trSmooth.setSampleRate(sampleRate, 0.3);

delayL.setSize(512 * int(sampleRate / 44100));
delayR.setSize(512 * int(sampleRate / 44100));
}
}

void RefineDsp::setLow (float gain)
{
gainLow = gain;
}

void RefineDsp::setMid (float gain)
{
gainMid = gain;
}

void RefineDsp::setHigh (float gain)
{
gainHigh = gain;
}

void RefineDsp::setX2Mode (bool enabled)
{
x2Mode = enabled;
}

void RefineDsp::processBlock (float* dataL, float* dataR, int numSamples)
{
const float x2gain = x2Mode ? 1.9475f : 1.f;

if (dataR != nullptr)
noise.processBlock(dataL, dataR, numSamples);
else
noise.processBlock(dataL, numSamples);

delayL.processBlock(dataL, numSamples);

if (dataR != nullptr)
delayR.processBlock(dataR, numSamples);

{
ScopedLock lock(processLock);

if (dataR != nullptr)
levelHold.processBlock(dataL, dataR, numSamples);
else
levelHold.processBlock(dataL, dataL, numSamples);

const float release = 1.f - 1.f / float(sampleRate * 0.001 * 100);

if (dataR == nullptr)
dataR = dataL;

for (int i=0; i<numSamples; ++i)
{
if (std::abs(dataL[i]) < 1e-8f)
dataL[i] = 0;

if (std::abs(dataR[i]) < 1e-8f)
dataR[i] = 0;

float x = 0.5f * (dataL[i] + dataR[i]);

if (x > -1e-4f && x < 1e-4f)
x = 0;

double r300 = rms300.process(x);

if (r300 != 0. && r300 < 1e-8f)
{
rms300.clear();
r300 = 0;
}

double r5 = rms5.process(x);

if (r5 != 0. && r5 < 1e-8f)
{
r5 = 0;
rms5.clear();
}

const float y = r300 > 0 ? (float) jlimit(0., 1., (r5 / r300 - 1.)) : 0.f;

trSmooth.processAttack(y*y);
const float lHold = levelHold.getValue();
const float r300s = (float) sqrt(jmax(0., r300));
level = lHold > 0 ? jlimit(0.f, 1.f, 1.4142f * r300s / lHold) : 0;
jassert(level >= 0 && level < 1e8);

const float newTrans = jmin(1.f, trSmooth.getValue()) * jmin<float>(1.f, sqrt(level) * 20.f);
transient = newTrans > transient ? newTrans : transient * release;

const float newNonTransient = (1 - pow(newTrans, 0.2f)) * jmin<float>(1.f, sqrt(level) * 20.f);
nonTransient = newNonTransient > nonTransient ? newNonTransient : nonTransient * release;

colorProc.add(transient, nonTransient, level);

if (rms.process(dataL[i], dataR[i]))
{
colors.push(colorProc.getColor());
}
}
}

if (gainLow > 0)
{
if (dataL != nullptr)
{
memcpy(auxLowL, dataL, numSamples * sizeof(float));
lowL.processBlock(auxLowL, numSamples);
}

if (dataR != nullptr)
{
memcpy(auxLowR, dataR, numSamples * sizeof(float));
lowR.processBlock(auxLowR, numSamples);
}
}

if (gainHigh > 0)
{
if (dataL != nullptr)
{
memcpy(auxHighL, dataL, numSamples * sizeof(float));
highL.processBlock(auxHighL, numSamples);
}

if (dataR != nullptr)
{
memcpy(auxHighR, dataR, numSamples * sizeof(float));
highR.processBlock(auxHighR, numSamples);
}
}

if (gainMid > 0)
{
const float gain = pow(10.f, x2gain * 1.25f * sqrt(gainMid) / 20.f);

if (dataL != nullptr)
{
for (int i=0; i<numSamples; ++i)
dataL[i] *= gain;
}

if (dataR != nullptr)
{
for (int i=0; i<numSamples; ++i)
dataR[i] *= gain;
}
}

if (gainLow > 0)
{
const float gain = pow(10.f, x2gain * 0.95f * sqrt(gainLow) / 20.f) - 1.f;

if (dataL != nullptr)
{
for (int i=0; i<numSamples; ++i)
dataL[i] += auxLowL[i] * gain;
}

if (dataR != nullptr)
{
for (int i=0; i<numSamples; ++i)
dataR[i] += auxLowR[i] * gain;
}
}

if (gainHigh > 0)
{
const float gain = pow(10.f, x2gain * 1.28f * sqrt(gainHigh) / 20.f) - 1.f;

if (dataL != nullptr)
{
for (int i=0; i<numSamples; ++i)
dataL[i] += auxHighL[i] * gain;
}

if (dataR != nullptr)
{
for (int i=0; i<numSamples; ++i)
dataR[i] += auxHighR[i] * gain;
}
}
}

float RefineDsp::getTransient() const
{
return transient;
}

float RefineDsp::getNonTransient() const
{
return nonTransient;
}

float RefineDsp::getLevel() const
{
return level;
}


bool RefineDsp::getRmsData (Array<float>& d, Array<uint32>& c) const
{
{
ScopedTryLock lock(processLock);

if (! lock.isLocked() || c.size() >= colors.getSize())
return false;

for (int i=0; i<c.size(); ++i)
c.getReference(i) = colors[i];
}

return rms.getData(d);
}




+ 185
- 0
ports/refine/source/RefineDsp.h View File

@@ -0,0 +1,185 @@
#ifndef SEPDSP_H_INCLUDED
#define SEPDSP_H_INCLUDED

#include "JuceHeader.h"
#include "Analyzer.h"
#include "Buffers.h"
#include "MiscDsp.h"

class LevelHold
{
public:
LevelHold()
{
setSampleRate(44100);
clear();
}

void setSampleRate (double sampleRate, double releaseTime = 1)
{
attack = 1 / (0.25 * releaseTime * sampleRate);
release = 1 - 1 / (releaseTime * sampleRate);
}

void clear()
{
value = 0;
}

void process (double x)
{
value *= release;

if (value < 1e-8)
value = 0;

if (x > value)
value = x;
}

void processAttack (double x)
{
value *= release;

if (value < 1e-8)
value = 0;

if (x > value)
value = value + (x - value) * attack;
}

void processBlock (const float* inL, const float* inR, int numSamples)
{
for (int i=0; i<numSamples; ++i)
{
const double x = 0.5 * (inL[i] + inR[i]);
process(x);
}
}

float getValue()
{
return (float) value;
}

private:

double attack;
double release;
double value;

};



class RefineDsp
{
public:
RefineDsp();

void clear();

void setBlockSize(int newBlockSize);
void setSampleRate(double newSampleRate);
void setLow(float gain);
void setMid(float gain);
void setHigh(float gain);
void setX2Mode(bool enabled);

void processBlock(float* dataL, float* dataR, int numSamples);

float getTransient() const;
float getNonTransient() const;
float getLevel() const;

bool getRmsData(Array<float>& d, Array<uint32>& c) const;

private:

struct ColorProc
{
ColorProc()
: transient (0), nonTransient (0), level (0)
{
}

void add (float tr, float ntr, float l)
{
transient += tr;
nonTransient += ntr;
level += l;
}

juce::uint32 getColor()
{
juce::uint32 ret = 0;

const float sum = transient + nonTransient + level;

if (sum > 0)
{
const juce::uint32 tr = juce::uint8(255 * transient / sum);
const juce::uint32 ntr = juce::uint8(255 * nonTransient / sum);
const juce::uint32 l = juce::uint8(255 * level / sum);

ret = (tr << 16) | (ntr << 8) | l;
}

transient = 0;
nonTransient = 0;
level = 0;
return ret;
}

float transient;
float nonTransient;
float level;
};


double sampleRate;

float gainLow;
float gainMid;
float gainHigh;
bool x2Mode;

float transient;
float nonTransient;
float level;

SimpleNoiseGen noise;

int auxSize;
juce::HeapBlock<float> auxLowL;
juce::HeapBlock<float> auxHighL;
juce::HeapBlock<float> auxLowR;
juce::HeapBlock<float> auxHighR;

StaticBiquad lowL;
StaticBiquad lowR;
StaticBiquad highL;
StaticBiquad highR;

StaticBiquad levelSlow;
StaticBiquad levelMid;
StaticBiquad levelFast;
RmsBuffer rms300;
RmsBuffer rms5;

LevelHold trSmooth;

LevelHold levelHold;

RmsEnvelope rms;
CircularBuffer<juce::uint32> colors;
ColorProc colorProc;

CircularBuffer<float> delayL;
CircularBuffer<float> delayR;

juce::CriticalSection processLock;
};

#endif // SEPDSP_H_INCLUDED

BIN
ports/refine/source/Ressources/background.png View File

Before After
Width: 450  |  Height: 300  |  Size: 49KB

BIN
ports/refine/source/Ressources/blue.png View File

Before After
Width: 64  |  Height: 960  |  Size: 65KB

BIN
ports/refine/source/Ressources/green.png View File

Before After
Width: 64  |  Height: 960  |  Size: 65KB

BIN
ports/refine/source/Ressources/red.png View File

Before After
Width: 64  |  Height: 960  |  Size: 65KB

BIN
ports/refine/source/Ressources/vu_blue.png View File

Before After
Width: 64  |  Height: 960  |  Size: 13KB

BIN
ports/refine/source/Ressources/vu_green.png View File

Before After
Width: 64  |  Height: 960  |  Size: 13KB

BIN
ports/refine/source/Ressources/vu_red.png View File

Before After
Width: 64  |  Height: 960  |  Size: 13KB

BIN
ports/refine/source/Ressources/x2button.png View File

Before After
Width: 32  |  Height: 32  |  Size: 2.3KB

+ 127
- 0
ports/refine/source/Visualisation.cpp View File

@@ -0,0 +1,127 @@
#include "Visualisation.h"

Visualisation::Visualisation (const RefineDsp& dsp)
: sepDsp (dsp),
minMag (-30.f),
maxMag (0.f)
{
setOpaque(true);
startTimer(100);
}

Visualisation::~Visualisation()
{
}

void Visualisation::paint (Graphics& g)
{
g.fillAll(Colour(0xFF101010));
const int w = jmin(rmsData.size(), colourData.size(), getWidth());
const float yBottom = getHeight() - 1.f;

for (int i = 0; i<w; ++i)
{
const int idx = w - 1 - i;
const float mag = jlimit(0.f, 1.f, rmsData.getReference(idx));
const float y = magToY(mag);
g.setColour(Colour(colourData.getReference(idx)));
g.drawVerticalLine(i, y, yBottom);
}
}

void Visualisation::resized()
{
const int w = getWidth();
rmsData.clearQuick();
colourData.clearQuick();
rmsData.ensureStorageAllocated(w);
colourData.ensureStorageAllocated(w);

for (int i = 0; i < w; ++i)
{
rmsData.add(0.f);
colourData.add(0);
}
}

void Visualisation::timerCallback()
{
if (sepDsp.getRmsData(rmsData, colourData))
{

float newMin = 10;
float newMax = 0;
float newMean = 0;
int meanSize = 0;

const Colour red(191, 0, 48);
const Colour green(0, 191, 44);
const Colour blue(0, 96, 191);

for (int i = 0; i<rmsData.size(); ++i)
{
if (rmsData.getReference(i) < 1e-8f)
{
rmsData.getReference(i) = -80.f;
continue;
}

newMean += rmsData.getReference(i);
++meanSize;

const float curMean = newMean / meanSize;
const float x = rmsData.getReference(i);
const float weight = 0.2f + 0.8f * sqrt(1.f - i / (rmsData.size() - 1.f));

const float xMin = curMean - weight * (curMean - x);
const float xMax = curMean + weight * (x - curMean);

newMin = jmin(newMin, xMin);
newMax = jmax(newMax, xMax);

rmsData.getReference(i) = 10 * log10(rmsData.getReference(i));

{
const float mulBlue = ((colourData.getReference(i) >> 16) & 0xFF) / 255.f;
const float mulGreen = ((colourData.getReference(i) >> 8) & 0xFF) / 255.f;
const float mulRed = ((colourData.getReference(i)) & 0xFF) / 255.f;

uint8_t r = uint8_t(blue.getRed()*mulBlue + green.getRed()*mulGreen + red.getRed()*mulRed);
uint8_t g = uint8_t(blue.getGreen()*mulBlue + green.getGreen()*mulGreen + red.getGreen()*mulRed);
uint8_t b = uint8_t(blue.getBlue()*mulBlue + green.getBlue()*mulGreen + red.getBlue()*mulRed);

r = 64 + r / 2;
g = 64 + g / 2;
b = 64 + b / 2;

colourData.getReference(i) = (255 << 24) | (r << 16) | (g << 8) | (b << 0);
}
}

if (newMin < 10 && newMin > 0)
{
newMean /= meanSize;

const float dist = jmax(0.01f, jmin(newMax - newMean, newMean - newMin));

newMin = jmax(1e-8f, jmin(0.9f*newMin, newMean - dist));
newMax = jmax(1.1f*newMax, newMean + dist);

const float minDb = 10 * std::log10(newMin);
const float maxDb = 10 * std::log10(newMax);

minMag = minMag*0.95f + 0.05f*minDb;
maxMag = maxMag*0.95f + 0.05f*maxDb;
}

for (int i = 0; i<rmsData.size(); ++i)
rmsData.getReference(i) = jlimit(0.f, 1.f, float((rmsData.getReference(i) - minMag) / (maxMag - minMag)));
repaint();
}
}

float Visualisation::magToY (float mag) const
{
return 1.f + (getHeight() - 2.f) * (1.f - mag);
}

+ 31
- 0
ports/refine/source/Visualisation.h View File

@@ -0,0 +1,31 @@
#ifndef VISUALISATION_H_INCLUDED
#define VISUALISATION_H_INCLUDED

#include "JuceHeader.h"
#include "RefineDsp.h"

class Visualisation : public Component, public Timer
{
public:
Visualisation (const RefineDsp& dsp);
~Visualisation();

void paint (Graphics& g);
void resized();
void timerCallback();
float magToY (float mag) const;

private:

const RefineDsp& sepDsp;
Array<float> rmsData;
Array<uint32> colourData;

float minMag;
float maxMag;

JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Visualisation)
};


#endif // VISUALISATION_H_INCLUDED

+ 98
- 0
ports/refine/source/ffft/Array.h View File

@@ -0,0 +1,98 @@
/*****************************************************************************

Array.h
By Laurent de Soras

--- Legal stuff ---

This program is free software. It comes without any warranty, to
the extent permitted by applicable law. You can redistribute it
and/or modify it under the terms of the Do What The Fuck You Want
To Public License, Version 2, as published by Sam Hocevar. See
http://sam.zoy.org/wtfpl/COPYING for more details.

*Tab=3***********************************************************************/



#if ! defined (ffft_Array_HEADER_INCLUDED)
#define ffft_Array_HEADER_INCLUDED

#if defined (_MSC_VER)
#pragma once
#pragma warning (4 : 4250) // "Inherits via dominance."
#endif



/*\\\ INCLUDE FILES \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/



namespace ffft
{



template <class T, long LEN>
class Array
{

/*\\\ PUBLIC \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/

public:

typedef T DataType;

Array ();

inline const DataType &
operator [] (long pos) const;
inline DataType &
operator [] (long pos);

static inline long
size ();



/*\\\ PROTECTED \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/

protected:



/*\\\ PRIVATE \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/

private:

DataType _data_arr [LEN];



/*\\\ FORBIDDEN MEMBER FUNCTIONS \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/

private:

Array (const Array &other);
Array & operator = (const Array &other);
bool operator == (const Array &other);
bool operator != (const Array &other);

}; // class Array



} // namespace ffft



#include "ffft/Array.hpp"



#endif // ffft_Array_HEADER_INCLUDED



/*\\\ EOF \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/

+ 99
- 0
ports/refine/source/ffft/Array.hpp View File

@@ -0,0 +1,99 @@
/*****************************************************************************

Array.hpp
By Laurent de Soras

--- Legal stuff ---

This program is free software. It comes without any warranty, to
the extent permitted by applicable law. You can redistribute it
and/or modify it under the terms of the Do What The Fuck You Want
To Public License, Version 2, as published by Sam Hocevar. See
http://sam.zoy.org/wtfpl/COPYING for more details.

*Tab=3***********************************************************************/



#if defined (ffft_Array_CURRENT_CODEHEADER)
#error Recursive inclusion of Array code header.
#endif
#define ffft_Array_CURRENT_CODEHEADER

#if ! defined (ffft_Array_CODEHEADER_INCLUDED)
#define ffft_Array_CODEHEADER_INCLUDED



/*\\\ INCLUDE FILES \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/

#include <cassert>



namespace ffft
{



/*\\\ PUBLIC \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/



template <class T, long LEN>
Array <T, LEN>::Array ()
{
// Nothing
}



template <class T, long LEN>
const typename Array <T, LEN>::DataType & Array <T, LEN>::operator [] (long pos) const
{
assert (pos >= 0);
assert (pos < LEN);

return (_data_arr [pos]);
}



template <class T, long LEN>
typename Array <T, LEN>::DataType & Array <T, LEN>::operator [] (long pos)
{
assert (pos >= 0);
assert (pos < LEN);

return (_data_arr [pos]);
}



template <class T, long LEN>
long Array <T, LEN>::size ()
{
return (LEN);
}



/*\\\ PROTECTED \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/



/*\\\ PRIVATE \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/



} // namespace ffft



#endif // ffft_Array_CODEHEADER_INCLUDED

#undef ffft_Array_CURRENT_CODEHEADER



/*\\\ EOF \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/

+ 101
- 0
ports/refine/source/ffft/DynArray.h View File

@@ -0,0 +1,101 @@
/*****************************************************************************

DynArray.h
By Laurent de Soras

--- Legal stuff ---

This program is free software. It comes without any warranty, to
the extent permitted by applicable law. You can redistribute it
and/or modify it under the terms of the Do What The Fuck You Want
To Public License, Version 2, as published by Sam Hocevar. See
http://sam.zoy.org/wtfpl/COPYING for more details.

*Tab=3***********************************************************************/



#if ! defined (ffft_DynArray_HEADER_INCLUDED)
#define ffft_DynArray_HEADER_INCLUDED

#if defined (_MSC_VER)
#pragma once
#pragma warning (4 : 4250) // "Inherits via dominance."
#endif



/*\\\ INCLUDE FILES \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/



namespace ffft
{



template <class T>
class DynArray
{

/*\\\ PUBLIC \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/

public:

typedef T DataType;

DynArray ();
explicit DynArray (long size);
~DynArray ();

inline long size () const;
inline void resize (long size);

inline const DataType &
operator [] (long pos) const;
inline DataType &
operator [] (long pos);



/*\\\ PROTECTED \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/

protected:



/*\\\ PRIVATE \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/

private:

DataType * _data_ptr;
long _len;



/*\\\ FORBIDDEN MEMBER FUNCTIONS \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/

private:

DynArray (const DynArray &other);
DynArray & operator = (const DynArray &other);
bool operator == (const DynArray &other);
bool operator != (const DynArray &other);

}; // class DynArray



} // namespace ffft



#include "DynArray.hpp"



#endif // ffft_DynArray_HEADER_INCLUDED



/*\\\ EOF \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/

+ 144
- 0
ports/refine/source/ffft/DynArray.hpp View File

@@ -0,0 +1,144 @@
/*****************************************************************************

DynArray.hpp
By Laurent de Soras

--- Legal stuff ---

This program is free software. It comes without any warranty, to
the extent permitted by applicable law. You can redistribute it
and/or modify it under the terms of the Do What The Fuck You Want
To Public License, Version 2, as published by Sam Hocevar. See
http://sam.zoy.org/wtfpl/COPYING for more details.

*Tab=3***********************************************************************/



#if defined (ffft_DynArray_CURRENT_CODEHEADER)
#error Recursive inclusion of DynArray code header.
#endif
#define ffft_DynArray_CURRENT_CODEHEADER

#if ! defined (ffft_DynArray_CODEHEADER_INCLUDED)
#define ffft_DynArray_CODEHEADER_INCLUDED



/*\\\ INCLUDE FILES \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/

#include <cassert>



namespace ffft
{



/*\\\ PUBLIC \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/



template <class T>
DynArray <T>::DynArray ()
: _data_ptr (0)
, _len (0)
{
// Nothing
}



template <class T>
DynArray <T>::DynArray (long size)
: _data_ptr (0)
, _len (0)
{
assert (size >= 0);
if (size > 0)
{
_data_ptr = new DataType [size];
_len = size;
}
}



template <class T>
DynArray <T>::~DynArray ()
{
delete [] _data_ptr;
_data_ptr = 0;
_len = 0;
}



template <class T>
long DynArray <T>::size () const
{
return (_len);
}



template <class T>
void DynArray <T>::resize (long size)
{
assert (size >= 0);
if (size > 0)
{
DataType * old_data_ptr = _data_ptr;
DataType * tmp_data_ptr = new DataType [size];

_data_ptr = tmp_data_ptr;
_len = size;

delete [] old_data_ptr;
}
}



template <class T>
const typename DynArray <T>::DataType & DynArray <T>::operator [] (long pos) const
{
assert (pos >= 0);
assert (pos < _len);

return (_data_ptr [pos]);
}



template <class T>
typename DynArray <T>::DataType & DynArray <T>::operator [] (long pos)
{
assert (pos >= 0);
assert (pos < _len);

return (_data_ptr [pos]);
}



/*\\\ PROTECTED \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/



/*\\\ PRIVATE \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/



} // namespace ffft



#endif // ffft_DynArray_CODEHEADER_INCLUDED

#undef ffft_DynArray_CURRENT_CODEHEADER



/*\\\ EOF \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/

+ 146
- 0
ports/refine/source/ffft/FFTReal.h View File

@@ -0,0 +1,146 @@
/*****************************************************************************

FFTReal.h
By Laurent de Soras

--- Legal stuff ---

This program is free software. It comes without any warranty, to
the extent permitted by applicable law. You can redistribute it
and/or modify it under the terms of the Do What The Fuck You Want
To Public License, Version 2, as published by Sam Hocevar. See
http://sam.zoy.org/wtfpl/COPYING for more details.

*Tab=3***********************************************************************/



#if ! defined (ffft_FFTReal_HEADER_INCLUDED)
#define ffft_FFTReal_HEADER_INCLUDED

#if defined (_MSC_VER)
#pragma once
#pragma warning (4 : 4250) // "Inherits via dominance."
#endif



/*\\\ INCLUDE FILES \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/

#include "def.h"
#include "DynArray.h"
#include "OscSinCos.h"



namespace ffft
{



template <class DT>
class FFTReal
{

/*\\\ PUBLIC \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/

public:

enum { MAX_BIT_DEPTH = 30 }; // So length can be represented as long int

typedef DT DataType;

explicit FFTReal (long length);
virtual ~FFTReal () {}



long get_length () const;
void do_fft (DataType f [], const DataType x []) const;
void do_ifft (const DataType f [], DataType x []) const;
void rescale (DataType x []) const;
DataType * use_buffer () const;



/*\\\ PROTECTED \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/

protected:



/*\\\ PRIVATE \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/

private:

// Over this bit depth, we use direct calculation for sin/cos
enum { TRIGO_BD_LIMIT = 12 };

typedef OscSinCos <DataType> OscType;

void init_br_lut ();
void init_trigo_lut ();
void init_trigo_osc ();

ffft_FORCEINLINE const long *
get_br_ptr () const;
ffft_FORCEINLINE const DataType *
get_trigo_ptr (int level) const;
ffft_FORCEINLINE long
get_trigo_level_index (int level) const;

inline void compute_fft_general (DataType f [], const DataType x []) const;
inline void compute_direct_pass_1_2 (DataType df [], const DataType x []) const;
inline void compute_direct_pass_3 (DataType df [], const DataType sf []) const;
inline void compute_direct_pass_n (DataType df [], const DataType sf [], int pass) const;
inline void compute_direct_pass_n_lut (DataType df [], const DataType sf [], int pass) const;
inline void compute_direct_pass_n_osc (DataType df [], const DataType sf [], int pass) const;

inline void compute_ifft_general (const DataType f [], DataType x []) const;
inline void compute_inverse_pass_n (DataType df [], const DataType sf [], int pass) const;
inline void compute_inverse_pass_n_osc (DataType df [], const DataType sf [], int pass) const;
inline void compute_inverse_pass_n_lut (DataType df [], const DataType sf [], int pass) const;
inline void compute_inverse_pass_3 (DataType df [], const DataType sf []) const;
inline void compute_inverse_pass_1_2 (DataType x [], const DataType sf []) const;

const long _length;
const int _nbr_bits;
DynArray <long>
_br_lut;
DynArray <DataType>
_trigo_lut;
mutable DynArray <DataType>
_buffer;
mutable DynArray <OscType>
_trigo_osc;



/*\\\ FORBIDDEN MEMBER FUNCTIONS \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/

private:

FFTReal ();
FFTReal (const FFTReal &other);
FFTReal & operator = (const FFTReal &other);
bool operator == (const FFTReal &other);
bool operator != (const FFTReal &other);

}; // class FFTReal



} // namespace ffft



#include "FFTReal.hpp"



#endif // ffft_FFTReal_HEADER_INCLUDED



/*\\\ EOF \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/

+ 934
- 0
ports/refine/source/ffft/FFTReal.hpp View File

@@ -0,0 +1,934 @@
/*****************************************************************************

FFTReal.hpp
By Laurent de Soras

--- Legal stuff ---

This program is free software. It comes without any warranty, to
the extent permitted by applicable law. You can redistribute it
and/or modify it under the terms of the Do What The Fuck You Want
To Public License, Version 2, as published by Sam Hocevar. See
http://sam.zoy.org/wtfpl/COPYING for more details.

*Tab=3***********************************************************************/



#if defined (ffft_FFTReal_CURRENT_CODEHEADER)
#error Recursive inclusion of FFTReal code header.
#endif
#define ffft_FFTReal_CURRENT_CODEHEADER

#if ! defined (ffft_FFTReal_CODEHEADER_INCLUDED)
#define ffft_FFTReal_CODEHEADER_INCLUDED



/*\\\ INCLUDE FILES \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/

#include <cassert>
#include <cmath>



namespace ffft
{



static inline bool FFTReal_is_pow2 (long x)
{
assert (x > 0);

return ((x & -x) == x);
}



static inline int FFTReal_get_next_pow2 (long x)
{
--x;

int p = 0;
while ((x & ~0xFFFFL) != 0)
{
p += 16;
x >>= 16;
}
while ((x & ~0xFL) != 0)
{
p += 4;
x >>= 4;
}
while (x > 0)
{
++p;
x >>= 1;
}

return (p);
}



/*\\\ PUBLIC \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/



/*
==============================================================================
Name: ctor
Input parameters:
- length: length of the array on which we want to do a FFT. Range: power of
2 only, > 0.
Throws: std::bad_alloc
==============================================================================
*/

template <class DT>
FFTReal <DT>::FFTReal (long length)
: _length (length)
, _nbr_bits (FFTReal_get_next_pow2 (length))
, _br_lut ()
, _trigo_lut ()
, _buffer (length)
, _trigo_osc ()
{
assert (FFTReal_is_pow2 (length));
assert (_nbr_bits <= MAX_BIT_DEPTH);

init_br_lut ();
init_trigo_lut ();
init_trigo_osc ();
}





/*
void FFTReal <DT>::initFFT(long length)
{
_length = length;
_nbr_bits = FFTReal_get_next_pow2 (length);
_buffer = length;

assert (FFTReal_is_pow2 (length));
assert (_nbr_bits <= MAX_BIT_DEPTH);

init_br_lut ();
init_trigo_lut ();
init_trigo_osc ();
}
*/
/*
==============================================================================
Name: get_length
Description:
Returns the number of points processed by this FFT object.
Returns: The number of points, power of 2, > 0.
Throws: Nothing
==============================================================================
*/

template <class DT>
long FFTReal <DT>::get_length () const
{
return (_length);
}



/*
==============================================================================
Name: do_fft
Description:
Compute the FFT of the array.
Input parameters:
- x: pointer on the source array (time).
Output parameters:
- f: pointer on the destination array (frequencies).
f [0...length(x)/2] = real values,
f [length(x)/2+1...length(x)-1] = negative imaginary values of
coefficents 1...length(x)/2-1.
Throws: Nothing
==============================================================================
*/

template <class DT>
void FFTReal <DT>::do_fft (DataType f [], const DataType x []) const
{
assert (f != 0);
assert (f != use_buffer ());
assert (x != 0);
assert (x != use_buffer ());
assert (x != f);

// General case
if (_nbr_bits > 2)
{
compute_fft_general (f, x);
}

// 4-point FFT
else if (_nbr_bits == 2)
{
f [1] = x [0] - x [2];
f [3] = x [1] - x [3];

const DataType b_0 = x [0] + x [2];
const DataType b_2 = x [1] + x [3];
f [0] = b_0 + b_2;
f [2] = b_0 - b_2;
}

// 2-point FFT
else if (_nbr_bits == 1)
{
f [0] = x [0] + x [1];
f [1] = x [0] - x [1];
}

// 1-point FFT
else
{
f [0] = x [0];
}
}



/*
==============================================================================
Name: do_ifft
Description:
Compute the inverse FFT of the array. Note that data must be post-scaled:
IFFT (FFT (x)) = x * length (x).
Input parameters:
- f: pointer on the source array (frequencies).
f [0...length(x)/2] = real values
f [length(x)/2+1...length(x)-1] = negative imaginary values of
coefficents 1...length(x)/2-1.
Output parameters:
- x: pointer on the destination array (time).
Throws: Nothing
==============================================================================
*/

template <class DT>
void FFTReal <DT>::do_ifft (const DataType f [], DataType x []) const
{
assert (f != 0);
assert (f != use_buffer ());
assert (x != 0);
assert (x != use_buffer ());
assert (x != f);

// General case
if (_nbr_bits > 2)
{
compute_ifft_general (f, x);
}

// 4-point IFFT
else if (_nbr_bits == 2)
{
const DataType b_0 = f [0] + f [2];
const DataType b_2 = f [0] - f [2];

x [0] = b_0 + f [1] * 2;
x [2] = b_0 - f [1] * 2;
x [1] = b_2 + f [3] * 2;
x [3] = b_2 - f [3] * 2;
}

// 2-point IFFT
else if (_nbr_bits == 1)
{
x [0] = f [0] + f [1];
x [1] = f [0] - f [1];
}

// 1-point IFFT
else
{
x [0] = f [0];
}
}



/*
==============================================================================
Name: rescale
Description:
Scale an array by divide each element by its length. This function should
be called after FFT + IFFT.
Input parameters:
- x: pointer on array to rescale (time or frequency).
Throws: Nothing
==============================================================================
*/

template <class DT>
void FFTReal <DT>::rescale (DataType x []) const
{
const DataType mul = DataType (1.0 / _length);

if (_length < 4)
{
long i = _length - 1;
do
{
x [i] *= mul;
--i;
}
while (i >= 0);
}

else
{
assert ((_length & 3) == 0);

// Could be optimized with SIMD instruction sets (needs alignment check)
long i = _length - 4;
do
{
x [i + 0] *= mul;
x [i + 1] *= mul;
x [i + 2] *= mul;
x [i + 3] *= mul;
i -= 4;
}
while (i >= 0);
}
}



/*
==============================================================================
Name: use_buffer
Description:
Access the internal buffer, whose length is the FFT one.
Buffer content will be erased at each do_fft() / do_ifft() call!
This buffer cannot be used as:
- source for FFT or IFFT done with this object
- destination for FFT or IFFT done with this object
Returns:
Buffer start address
Throws: Nothing
==============================================================================
*/

template <class DT>
typename FFTReal <DT>::DataType * FFTReal <DT>::use_buffer () const
{
return (&_buffer [0]);
}



/*\\\ PROTECTED \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/



/*\\\ PRIVATE \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/



template <class DT>
void FFTReal <DT>::init_br_lut ()
{
const long length = 1L << _nbr_bits;
_br_lut.resize (length);

_br_lut [0] = 0;
long br_index = 0;
for (long cnt = 1; cnt < length; ++cnt)
{
// ++br_index (bit reversed)
long bit = length >> 1;
while (((br_index ^= bit) & bit) == 0)
{
bit >>= 1;
}

_br_lut [cnt] = br_index;
}
}



template <class DT>
void FFTReal <DT>::init_trigo_lut ()
{
using namespace std;

if (_nbr_bits > 3)
{
const long total_len = (1L << (_nbr_bits - 1)) - 4;
_trigo_lut.resize (total_len);

for (int level = 3; level < _nbr_bits; ++level)
{
const long level_len = 1L << (level - 1);
DataType * const level_ptr =
&_trigo_lut [get_trigo_level_index (level)];
const double mul = PI / (level_len << 1);

for (long i = 0; i < level_len; ++ i)
{
level_ptr [i] = static_cast <DataType> (cos (i * mul));
}
}
}
}



template <class DT>
void FFTReal <DT>::init_trigo_osc ()
{
const int nbr_osc = _nbr_bits - TRIGO_BD_LIMIT;
if (nbr_osc > 0)
{
_trigo_osc.resize (nbr_osc);

for (int osc_cnt = 0; osc_cnt < nbr_osc; ++osc_cnt)
{
OscType & osc = _trigo_osc [osc_cnt];

const long len = 1L << (TRIGO_BD_LIMIT + osc_cnt);
const double mul = (0.5 * PI) / len;
osc.set_step (mul);
}
}
}



template <class DT>
const long * FFTReal <DT>::get_br_ptr () const
{
return (&_br_lut [0]);
}



template <class DT>
const typename FFTReal <DT>::DataType * FFTReal <DT>::get_trigo_ptr (int level) const
{
assert (level >= 3);

return (&_trigo_lut [get_trigo_level_index (level)]);
}



template <class DT>
long FFTReal <DT>::get_trigo_level_index (int level) const
{
assert (level >= 3);

return ((1L << (level - 1)) - 4);
}



// Transform in several passes
template <class DT>
void FFTReal <DT>::compute_fft_general (DataType f [], const DataType x []) const
{
assert (f != 0);
assert (f != use_buffer ());
assert (x != 0);
assert (x != use_buffer ());
assert (x != f);

DataType * sf;
DataType * df;

if ((_nbr_bits & 1) != 0)
{
df = use_buffer ();
sf = f;
}
else
{
df = f;
sf = use_buffer ();
}

compute_direct_pass_1_2 (df, x);
compute_direct_pass_3 (sf, df);

for (int pass = 3; pass < _nbr_bits; ++ pass)
{
compute_direct_pass_n (df, sf, pass);

DataType * const temp_ptr = df;
df = sf;
sf = temp_ptr;
}
}



template <class DT>
void FFTReal <DT>::compute_direct_pass_1_2 (DataType df [], const DataType x []) const
{
assert (df != 0);
assert (x != 0);
assert (df != x);

const long * const bit_rev_lut_ptr = get_br_ptr ();
long coef_index = 0;
do
{
const long rev_index_0 = bit_rev_lut_ptr [coef_index];
const long rev_index_1 = bit_rev_lut_ptr [coef_index + 1];
const long rev_index_2 = bit_rev_lut_ptr [coef_index + 2];
const long rev_index_3 = bit_rev_lut_ptr [coef_index + 3];

DataType * const df2 = df + coef_index;
df2 [1] = x [rev_index_0] - x [rev_index_1];
df2 [3] = x [rev_index_2] - x [rev_index_3];

const DataType sf_0 = x [rev_index_0] + x [rev_index_1];
const DataType sf_2 = x [rev_index_2] + x [rev_index_3];

df2 [0] = sf_0 + sf_2;
df2 [2] = sf_0 - sf_2;
coef_index += 4;
}
while (coef_index < _length);
}



template <class DT>
void FFTReal <DT>::compute_direct_pass_3 (DataType df [], const DataType sf []) const
{
assert (df != 0);
assert (sf != 0);
assert (df != sf);

const DataType sqrt2_2 = DataType (SQRT2 * 0.5);
long coef_index = 0;
do
{
DataType v;

df [coef_index] = sf [coef_index] + sf [coef_index + 4];
df [coef_index + 4] = sf [coef_index] - sf [coef_index + 4];
df [coef_index + 2] = sf [coef_index + 2];
df [coef_index + 6] = sf [coef_index + 6];

v = (sf [coef_index + 5] - sf [coef_index + 7]) * sqrt2_2;
df [coef_index + 1] = sf [coef_index + 1] + v;
df [coef_index + 3] = sf [coef_index + 1] - v;

v = (sf [coef_index + 5] + sf [coef_index + 7]) * sqrt2_2;
df [coef_index + 5] = v + sf [coef_index + 3];
df [coef_index + 7] = v - sf [coef_index + 3];

coef_index += 8;
}
while (coef_index < _length);
}



template <class DT>
void FFTReal <DT>::compute_direct_pass_n (DataType df [], const DataType sf [], int pass) const
{
assert (df != 0);
assert (sf != 0);
assert (df != sf);
assert (pass >= 3);
assert (pass < _nbr_bits);

if (pass <= TRIGO_BD_LIMIT)
{
compute_direct_pass_n_lut (df, sf, pass);
}
else
{
compute_direct_pass_n_osc (df, sf, pass);
}
}



template <class DT>
void FFTReal <DT>::compute_direct_pass_n_lut (DataType df [], const DataType sf [], int pass) const
{
assert (df != 0);
assert (sf != 0);
assert (df != sf);
assert (pass >= 3);
assert (pass < _nbr_bits);

const long nbr_coef = 1 << pass;
const long h_nbr_coef = nbr_coef >> 1;
const long d_nbr_coef = nbr_coef << 1;
long coef_index = 0;
const DataType * const cos_ptr = get_trigo_ptr (pass);
do
{
const DataType * const sf1r = sf + coef_index;
const DataType * const sf2r = sf1r + nbr_coef;
DataType * const dfr = df + coef_index;
DataType * const dfi = dfr + nbr_coef;

// Extreme coefficients are always real
dfr [0] = sf1r [0] + sf2r [0];
dfi [0] = sf1r [0] - sf2r [0]; // dfr [nbr_coef] =
dfr [h_nbr_coef] = sf1r [h_nbr_coef];
dfi [h_nbr_coef] = sf2r [h_nbr_coef];

// Others are conjugate complex numbers
const DataType * const sf1i = sf1r + h_nbr_coef;
const DataType * const sf2i = sf1i + nbr_coef;
for (long i = 1; i < h_nbr_coef; ++ i)
{
const DataType c = cos_ptr [i]; // cos (i*PI/nbr_coef);
const DataType s = cos_ptr [h_nbr_coef - i]; // sin (i*PI/nbr_coef);
DataType v;

v = sf2r [i] * c - sf2i [i] * s;
dfr [i] = sf1r [i] + v;
dfi [-i] = sf1r [i] - v; // dfr [nbr_coef - i] =

v = sf2r [i] * s + sf2i [i] * c;
dfi [i] = v + sf1i [i];
dfi [nbr_coef - i] = v - sf1i [i];
}

coef_index += d_nbr_coef;
}
while (coef_index < _length);
}



template <class DT>
void FFTReal <DT>::compute_direct_pass_n_osc (DataType df [], const DataType sf [], int pass) const
{
assert (df != 0);
assert (sf != 0);
assert (df != sf);
assert (pass > TRIGO_BD_LIMIT);
assert (pass < _nbr_bits);

const long nbr_coef = 1 << pass;
const long h_nbr_coef = nbr_coef >> 1;
const long d_nbr_coef = nbr_coef << 1;
long coef_index = 0;
OscType & osc = _trigo_osc [pass - (TRIGO_BD_LIMIT + 1)];
do
{
const DataType * const sf1r = sf + coef_index;
const DataType * const sf2r = sf1r + nbr_coef;
DataType * const dfr = df + coef_index;
DataType * const dfi = dfr + nbr_coef;

osc.clear_buffers ();

// Extreme coefficients are always real
dfr [0] = sf1r [0] + sf2r [0];
dfi [0] = sf1r [0] - sf2r [0]; // dfr [nbr_coef] =
dfr [h_nbr_coef] = sf1r [h_nbr_coef];
dfi [h_nbr_coef] = sf2r [h_nbr_coef];

// Others are conjugate complex numbers
const DataType * const sf1i = sf1r + h_nbr_coef;
const DataType * const sf2i = sf1i + nbr_coef;
for (long i = 1; i < h_nbr_coef; ++ i)
{
osc.step ();
const DataType c = osc.get_cos ();
const DataType s = osc.get_sin ();
DataType v;

v = sf2r [i] * c - sf2i [i] * s;
dfr [i] = sf1r [i] + v;
dfi [-i] = sf1r [i] - v; // dfr [nbr_coef - i] =

v = sf2r [i] * s + sf2i [i] * c;
dfi [i] = v + sf1i [i];
dfi [nbr_coef - i] = v - sf1i [i];
}

coef_index += d_nbr_coef;
}
while (coef_index < _length);
}



// Transform in several pass
template <class DT>
void FFTReal <DT>::compute_ifft_general (const DataType f [], DataType x []) const
{
assert (f != 0);
assert (f != use_buffer ());
assert (x != 0);
assert (x != use_buffer ());
assert (x != f);

DataType * sf = const_cast <DataType *> (f);
DataType * df;
DataType * df_temp;

if (_nbr_bits & 1)
{
df = use_buffer ();
df_temp = x;
}
else
{
df = x;
df_temp = use_buffer ();
}

for (int pass = _nbr_bits - 1; pass >= 3; -- pass)
{
compute_inverse_pass_n (df, sf, pass);

if (pass < _nbr_bits - 1)
{
DataType * const temp_ptr = df;
df = sf;
sf = temp_ptr;
}
else
{
sf = df;
df = df_temp;
}
}

compute_inverse_pass_3 (df, sf);
compute_inverse_pass_1_2 (x, df);
}



template <class DT>
void FFTReal <DT>::compute_inverse_pass_n (DataType df [], const DataType sf [], int pass) const
{
assert (df != 0);
assert (sf != 0);
assert (df != sf);
assert (pass >= 3);
assert (pass < _nbr_bits);

if (pass <= TRIGO_BD_LIMIT)
{
compute_inverse_pass_n_lut (df, sf, pass);
}
else
{
compute_inverse_pass_n_osc (df, sf, pass);
}
}



template <class DT>
void FFTReal <DT>::compute_inverse_pass_n_lut (DataType df [], const DataType sf [], int pass) const
{
assert (df != 0);
assert (sf != 0);
assert (df != sf);
assert (pass >= 3);
assert (pass < _nbr_bits);

const long nbr_coef = 1 << pass;
const long h_nbr_coef = nbr_coef >> 1;
const long d_nbr_coef = nbr_coef << 1;
long coef_index = 0;
const DataType * const cos_ptr = get_trigo_ptr (pass);
do
{
const DataType * const sfr = sf + coef_index;
const DataType * const sfi = sfr + nbr_coef;
DataType * const df1r = df + coef_index;
DataType * const df2r = df1r + nbr_coef;

// Extreme coefficients are always real
df1r [0] = sfr [0] + sfi [0]; // + sfr [nbr_coef]
df2r [0] = sfr [0] - sfi [0]; // - sfr [nbr_coef]
df1r [h_nbr_coef] = sfr [h_nbr_coef] * 2;
df2r [h_nbr_coef] = sfi [h_nbr_coef] * 2;

// Others are conjugate complex numbers
DataType * const df1i = df1r + h_nbr_coef;
DataType * const df2i = df1i + nbr_coef;
for (long i = 1; i < h_nbr_coef; ++ i)
{
df1r [i] = sfr [i] + sfi [-i]; // + sfr [nbr_coef - i]
df1i [i] = sfi [i] - sfi [nbr_coef - i];

const DataType c = cos_ptr [i]; // cos (i*PI/nbr_coef);
const DataType s = cos_ptr [h_nbr_coef - i]; // sin (i*PI/nbr_coef);
const DataType vr = sfr [i] - sfi [-i]; // - sfr [nbr_coef - i]
const DataType vi = sfi [i] + sfi [nbr_coef - i];

df2r [i] = vr * c + vi * s;
df2i [i] = vi * c - vr * s;
}

coef_index += d_nbr_coef;
}
while (coef_index < _length);
}



template <class DT>
void FFTReal <DT>::compute_inverse_pass_n_osc (DataType df [], const DataType sf [], int pass) const
{
assert (df != 0);
assert (sf != 0);
assert (df != sf);
assert (pass > TRIGO_BD_LIMIT);
assert (pass < _nbr_bits);

const long nbr_coef = 1 << pass;
const long h_nbr_coef = nbr_coef >> 1;
const long d_nbr_coef = nbr_coef << 1;
long coef_index = 0;
OscType & osc = _trigo_osc [pass - (TRIGO_BD_LIMIT + 1)];
do
{
const DataType * const sfr = sf + coef_index;
const DataType * const sfi = sfr + nbr_coef;
DataType * const df1r = df + coef_index;
DataType * const df2r = df1r + nbr_coef;

osc.clear_buffers ();

// Extreme coefficients are always real
df1r [0] = sfr [0] + sfi [0]; // + sfr [nbr_coef]
df2r [0] = sfr [0] - sfi [0]; // - sfr [nbr_coef]
df1r [h_nbr_coef] = sfr [h_nbr_coef] * 2;
df2r [h_nbr_coef] = sfi [h_nbr_coef] * 2;

// Others are conjugate complex numbers
DataType * const df1i = df1r + h_nbr_coef;
DataType * const df2i = df1i + nbr_coef;
for (long i = 1; i < h_nbr_coef; ++ i)
{
df1r [i] = sfr [i] + sfi [-i]; // + sfr [nbr_coef - i]
df1i [i] = sfi [i] - sfi [nbr_coef - i];

osc.step ();
const DataType c = osc.get_cos ();
const DataType s = osc.get_sin ();
const DataType vr = sfr [i] - sfi [-i]; // - sfr [nbr_coef - i]
const DataType vi = sfi [i] + sfi [nbr_coef - i];

df2r [i] = vr * c + vi * s;
df2i [i] = vi * c - vr * s;
}

coef_index += d_nbr_coef;
}
while (coef_index < _length);
}



template <class DT>
void FFTReal <DT>::compute_inverse_pass_3 (DataType df [], const DataType sf []) const
{
assert (df != 0);
assert (sf != 0);
assert (df != sf);

const DataType sqrt2_2 = DataType (SQRT2 * 0.5);
long coef_index = 0;
do
{
df [coef_index] = sf [coef_index] + sf [coef_index + 4];
df [coef_index + 4] = sf [coef_index] - sf [coef_index + 4];
df [coef_index + 2] = sf [coef_index + 2] * 2;
df [coef_index + 6] = sf [coef_index + 6] * 2;

df [coef_index + 1] = sf [coef_index + 1] + sf [coef_index + 3];
df [coef_index + 3] = sf [coef_index + 5] - sf [coef_index + 7];

const DataType vr = sf [coef_index + 1] - sf [coef_index + 3];
const DataType vi = sf [coef_index + 5] + sf [coef_index + 7];

df [coef_index + 5] = (vr + vi) * sqrt2_2;
df [coef_index + 7] = (vi - vr) * sqrt2_2;

coef_index += 8;
}
while (coef_index < _length);
}



template <class DT>
void FFTReal <DT>::compute_inverse_pass_1_2 (DataType x [], const DataType sf []) const
{
assert (x != 0);
assert (sf != 0);
assert (x != sf);

const long * bit_rev_lut_ptr = get_br_ptr ();
const DataType * sf2 = sf;
long coef_index = 0;
do
{
{
const DataType b_0 = sf2 [0] + sf2 [2];
const DataType b_2 = sf2 [0] - sf2 [2];
const DataType b_1 = sf2 [1] * 2;
const DataType b_3 = sf2 [3] * 2;

x [bit_rev_lut_ptr [0]] = b_0 + b_1;
x [bit_rev_lut_ptr [1]] = b_0 - b_1;
x [bit_rev_lut_ptr [2]] = b_2 + b_3;
x [bit_rev_lut_ptr [3]] = b_2 - b_3;
}
{
const DataType b_0 = sf2 [4] + sf2 [6];
const DataType b_2 = sf2 [4] - sf2 [6];
const DataType b_1 = sf2 [5] * 2;
const DataType b_3 = sf2 [7] * 2;

x [bit_rev_lut_ptr [4]] = b_0 + b_1;
x [bit_rev_lut_ptr [5]] = b_0 - b_1;
x [bit_rev_lut_ptr [6]] = b_2 + b_3;
x [bit_rev_lut_ptr [7]] = b_2 - b_3;
}

sf2 += 8;
coef_index += 8;
bit_rev_lut_ptr += 8;
}
while (coef_index < _length);
}



} // namespace ffft



#endif // ffft_FFTReal_CODEHEADER_INCLUDED

#undef ffft_FFTReal_CURRENT_CODEHEADER



/*\\\ EOF \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/

+ 131
- 0
ports/refine/source/ffft/FFTRealFixLen.h View File

@@ -0,0 +1,131 @@
/*****************************************************************************

FFTRealFixLen.h
By Laurent de Soras

--- Legal stuff ---

This program is free software. It comes without any warranty, to
the extent permitted by applicable law. You can redistribute it
and/or modify it under the terms of the Do What The Fuck You Want
To Public License, Version 2, as published by Sam Hocevar. See
http://sam.zoy.org/wtfpl/COPYING for more details.

*Tab=3***********************************************************************/



#if ! defined (ffft_FFTRealFixLen_HEADER_INCLUDED)
#define ffft_FFTRealFixLen_HEADER_INCLUDED

#if defined (_MSC_VER)
#pragma once
#pragma warning (4 : 4250) // "Inherits via dominance."
#endif



/*\\\ INCLUDE FILES \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/

#include "ffft/Array.h"
#include "ffft/DynArray.h"
#include "ffft/FFTRealFixLenParam.h"
#include "ffft/OscSinCos.h"



namespace ffft
{



template <int LL2>
class FFTRealFixLen
{
typedef int CompileTimeCheck1 [(LL2 >= 0) ? 1 : -1];
typedef int CompileTimeCheck2 [(LL2 <= 30) ? 1 : -1];

/*\\\ PUBLIC \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/

public:

typedef FFTRealFixLenParam::DataType DataType;
typedef OscSinCos <DataType> OscType;

enum { FFT_LEN_L2 = LL2 };
enum { FFT_LEN = 1 << FFT_LEN_L2 };

FFTRealFixLen ();

inline long get_length () const;
void do_fft (DataType f [], const DataType x []);
void do_ifft (const DataType f [], DataType x []);
void rescale (DataType x []) const;



/*\\\ PROTECTED \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/

protected:



/*\\\ PRIVATE \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/

private:

enum { TRIGO_BD_LIMIT = FFTRealFixLenParam::TRIGO_BD_LIMIT };

enum { BR_ARR_SIZE_L2 = ((FFT_LEN_L2 - 3) < 0) ? 0 : (FFT_LEN_L2 - 2) };
enum { BR_ARR_SIZE = 1 << BR_ARR_SIZE_L2 };

enum { TRIGO_BD = ((FFT_LEN_L2 - TRIGO_BD_LIMIT) < 0)
? (int)FFT_LEN_L2
: (int)TRIGO_BD_LIMIT };
enum { TRIGO_TABLE_ARR_SIZE_L2 = (LL2 < 4) ? 0 : (TRIGO_BD - 2) };
enum { TRIGO_TABLE_ARR_SIZE = 1 << TRIGO_TABLE_ARR_SIZE_L2 };

enum { NBR_TRIGO_OSC = FFT_LEN_L2 - TRIGO_BD };
enum { TRIGO_OSC_ARR_SIZE = (NBR_TRIGO_OSC > 0) ? NBR_TRIGO_OSC : 1 };

void build_br_lut ();
void build_trigo_lut ();
void build_trigo_osc ();

DynArray <DataType>
_buffer;
DynArray <long>
_br_data;
DynArray <DataType>
_trigo_data;
Array <OscType, TRIGO_OSC_ARR_SIZE>
_trigo_osc;



/*\\\ FORBIDDEN MEMBER FUNCTIONS \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/

private:

FFTRealFixLen (const FFTRealFixLen &other);
FFTRealFixLen& operator = (const FFTRealFixLen &other);
bool operator == (const FFTRealFixLen &other);
bool operator != (const FFTRealFixLen &other);

}; // class FFTRealFixLen



} // namespace ffft



#include "ffft/FFTRealFixLen.hpp"



#endif // ffft_FFTRealFixLen_HEADER_INCLUDED



/*\\\ EOF \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/

+ 323
- 0
ports/refine/source/ffft/FFTRealFixLen.hpp View File

@@ -0,0 +1,323 @@
/*****************************************************************************

FFTRealFixLen.hpp
By Laurent de Soras

--- Legal stuff ---

This program is free software. It comes without any warranty, to
the extent permitted by applicable law. You can redistribute it
and/or modify it under the terms of the Do What The Fuck You Want
To Public License, Version 2, as published by Sam Hocevar. See
http://sam.zoy.org/wtfpl/COPYING for more details.

*Tab=3***********************************************************************/



#if defined (ffft_FFTRealFixLen_CURRENT_CODEHEADER)
#error Recursive inclusion of FFTRealFixLen code header.
#endif
#define ffft_FFTRealFixLen_CURRENT_CODEHEADER

#if ! defined (ffft_FFTRealFixLen_CODEHEADER_INCLUDED)
#define ffft_FFTRealFixLen_CODEHEADER_INCLUDED



/*\\\ INCLUDE FILES \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/

#include "ffft/def.h"
#include "ffft/FFTRealPassDirect.h"
#include "ffft/FFTRealPassInverse.h"
#include "ffft/FFTRealSelect.h"

#include <cassert>
#include <cmath>

namespace std { }



namespace ffft
{



/*\\\ PUBLIC \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/



template <int LL2>
FFTRealFixLen <LL2>::FFTRealFixLen ()
: _buffer (FFT_LEN)
, _br_data (BR_ARR_SIZE)
, _trigo_data (TRIGO_TABLE_ARR_SIZE)
, _trigo_osc ()
{
build_br_lut ();
build_trigo_lut ();
build_trigo_osc ();
}



template <int LL2>
long FFTRealFixLen <LL2>::get_length () const
{
return (FFT_LEN);
}



// General case
template <int LL2>
void FFTRealFixLen <LL2>::do_fft (DataType f [], const DataType x [])
{
assert (f != 0);
assert (x != 0);
assert (x != f);
assert (FFT_LEN_L2 >= 3);

// Do the transform in several passes
const DataType * cos_ptr = &_trigo_data [0];
const long * br_ptr = &_br_data [0];

FFTRealPassDirect <FFT_LEN_L2 - 1>::process (
FFT_LEN,
f,
&_buffer [0],
x,
cos_ptr,
TRIGO_TABLE_ARR_SIZE,
br_ptr,
&_trigo_osc [0]
);
}

// 4-point FFT
template <>
inline void FFTRealFixLen <2>::do_fft (DataType f [], const DataType x [])
{
assert (f != 0);
assert (x != 0);
assert (x != f);

f [1] = x [0] - x [2];
f [3] = x [1] - x [3];

const DataType b_0 = x [0] + x [2];
const DataType b_2 = x [1] + x [3];
f [0] = b_0 + b_2;
f [2] = b_0 - b_2;
}

// 2-point FFT
template <>
inline void FFTRealFixLen <1>::do_fft (DataType f [], const DataType x [])
{
assert (f != 0);
assert (x != 0);
assert (x != f);

f [0] = x [0] + x [1];
f [1] = x [0] - x [1];
}

// 1-point FFT
template <>
inline void FFTRealFixLen <0>::do_fft (DataType f [], const DataType x [])
{
assert (f != 0);
assert (x != 0);

f [0] = x [0];
}



// General case
template <int LL2>
void FFTRealFixLen <LL2>::do_ifft (const DataType f [], DataType x [])
{
assert (f != 0);
assert (x != 0);
assert (x != f);
assert (FFT_LEN_L2 >= 3);

// Do the transform in several passes
DataType * s_ptr =
FFTRealSelect <FFT_LEN_L2 & 1>::sel_bin (&_buffer [0], x);
DataType * d_ptr =
FFTRealSelect <FFT_LEN_L2 & 1>::sel_bin (x, &_buffer [0]);
const DataType * cos_ptr = &_trigo_data [0];
const long * br_ptr = &_br_data [0];

FFTRealPassInverse <FFT_LEN_L2 - 1>::process (
FFT_LEN,
d_ptr,
s_ptr,
f,
cos_ptr,
TRIGO_TABLE_ARR_SIZE,
br_ptr,
&_trigo_osc [0]
);
}

// 4-point IFFT
template <>
inline void FFTRealFixLen <2>::do_ifft (const DataType f [], DataType x [])
{
assert (f != 0);
assert (x != 0);
assert (x != f);

const DataType b_0 = f [0] + f [2];
const DataType b_2 = f [0] - f [2];

x [0] = b_0 + f [1] * 2;
x [2] = b_0 - f [1] * 2;
x [1] = b_2 + f [3] * 2;
x [3] = b_2 - f [3] * 2;
}

// 2-point IFFT
template <>
inline void FFTRealFixLen <1>::do_ifft (const DataType f [], DataType x [])
{
assert (f != 0);
assert (x != 0);
assert (x != f);

x [0] = f [0] + f [1];
x [1] = f [0] - f [1];
}

// 1-point IFFT
template <>
inline void FFTRealFixLen <0>::do_ifft (const DataType f [], DataType x [])
{
assert (f != 0);
assert (x != 0);
assert (x != f);

x [0] = f [0];
}




template <int LL2>
void FFTRealFixLen <LL2>::rescale (DataType x []) const
{
assert (x != 0);

const DataType mul = DataType (1.0 / FFT_LEN);

if (FFT_LEN < 4)
{
long i = FFT_LEN - 1;
do
{
x [i] *= mul;
--i;
}
while (i >= 0);
}

else
{
assert ((FFT_LEN & 3) == 0);

// Could be optimized with SIMD instruction sets (needs alignment check)
long i = FFT_LEN - 4;
do
{
x [i + 0] *= mul;
x [i + 1] *= mul;
x [i + 2] *= mul;
x [i + 3] *= mul;
i -= 4;
}
while (i >= 0);
}
}



/*\\\ PROTECTED \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/



/*\\\ PRIVATE \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/



template <int LL2>
void FFTRealFixLen <LL2>::build_br_lut ()
{
_br_data [0] = 0;
for (long cnt = 1; cnt < BR_ARR_SIZE; ++cnt)
{
long index = cnt << 2;
long br_index = 0;

int bit_cnt = FFT_LEN_L2;
do
{
br_index <<= 1;
br_index += (index & 1);
index >>= 1;

-- bit_cnt;
}
while (bit_cnt > 0);

_br_data [cnt] = br_index;
}
}



template <int LL2>
void FFTRealFixLen <LL2>::build_trigo_lut ()
{
const double mul = (0.5 * PI) / TRIGO_TABLE_ARR_SIZE;
for (long i = 0; i < TRIGO_TABLE_ARR_SIZE; ++ i)
{
using namespace std;

_trigo_data [i] = DataType (cos (i * mul));
}
}



template <int LL2>
void FFTRealFixLen <LL2>::build_trigo_osc ()
{
for (int i = 0; i < NBR_TRIGO_OSC; ++i)
{
OscType & osc = _trigo_osc [i];

const long len = static_cast <long> (TRIGO_TABLE_ARR_SIZE) << (i + 1);
const double mul = (0.5 * PI) / len;
osc.set_step (mul);
}
}



} // namespace ffft



#endif // ffft_FFTRealFixLen_CODEHEADER_INCLUDED

#undef ffft_FFTRealFixLen_CURRENT_CODEHEADER



/*\\\ EOF \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/

+ 90
- 0
ports/refine/source/ffft/FFTRealFixLenParam.h View File

@@ -0,0 +1,90 @@
/*****************************************************************************

FFTRealFixLenParam.h
By Laurent de Soras

--- Legal stuff ---

This program is free software. It comes without any warranty, to
the extent permitted by applicable law. You can redistribute it
and/or modify it under the terms of the Do What The Fuck You Want
To Public License, Version 2, as published by Sam Hocevar. See
http://sam.zoy.org/wtfpl/COPYING for more details.

*Tab=3***********************************************************************/



#if ! defined (ffft_FFTRealFixLenParam_HEADER_INCLUDED)
#define ffft_FFTRealFixLenParam_HEADER_INCLUDED

#if defined (_MSC_VER)
#pragma once
#pragma warning (4 : 4250) // "Inherits via dominance."
#endif



/*\\\ INCLUDE FILES \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/



namespace ffft
{



class FFTRealFixLenParam
{

/*\\\ PUBLIC \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/

public:

// Over this bit depth, we use direct calculation for sin/cos
enum { TRIGO_BD_LIMIT = 12 };

typedef float DataType;



/*\\\ PROTECTED \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/

protected:



/*\\\ PRIVATE \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/

private:



/*\\\ FORBIDDEN MEMBER FUNCTIONS \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/

private:

FFTRealFixLenParam ();
FFTRealFixLenParam (const FFTRealFixLenParam &other);
FFTRealFixLenParam &
operator = (const FFTRealFixLenParam &other);
bool operator == (const FFTRealFixLenParam &other);
bool operator != (const FFTRealFixLenParam &other);

}; // class FFTRealFixLenParam



} // namespace ffft



//#include "ffft/FFTRealFixLenParam.hpp"



#endif // ffft_FFTRealFixLenParam_HEADER_INCLUDED



/*\\\ EOF \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/

+ 96
- 0
ports/refine/source/ffft/FFTRealPassDirect.h View File

@@ -0,0 +1,96 @@
/*****************************************************************************

FFTRealPassDirect.h
By Laurent de Soras

--- Legal stuff ---

This program is free software. It comes without any warranty, to
the extent permitted by applicable law. You can redistribute it
and/or modify it under the terms of the Do What The Fuck You Want
To Public License, Version 2, as published by Sam Hocevar. See
http://sam.zoy.org/wtfpl/COPYING for more details.

*Tab=3***********************************************************************/



#if ! defined (ffft_FFTRealPassDirect_HEADER_INCLUDED)
#define ffft_FFTRealPassDirect_HEADER_INCLUDED

#if defined (_MSC_VER)
#pragma once
#pragma warning (4 : 4250) // "Inherits via dominance."
#endif



/*\\\ INCLUDE FILES \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/

#include "ffft/def.h"
#include "ffft/FFTRealFixLenParam.h"
#include "ffft/OscSinCos.h"



namespace ffft
{



template <int PASS>
class FFTRealPassDirect
{

/*\\\ PUBLIC \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/

public:

typedef FFTRealFixLenParam::DataType DataType;
typedef OscSinCos <DataType> OscType;

ffft_FORCEINLINE static void
process (long len, DataType dest_ptr [], DataType src_ptr [], const DataType x_ptr [], const DataType cos_ptr [], long cos_len, const long br_ptr [], OscType osc_list []);



/*\\\ PROTECTED \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/

protected:



/*\\\ PRIVATE \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/

private:



/*\\\ FORBIDDEN MEMBER FUNCTIONS \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/

private:

FFTRealPassDirect ();
FFTRealPassDirect (const FFTRealPassDirect &other);
FFTRealPassDirect &
operator = (const FFTRealPassDirect &other);
bool operator == (const FFTRealPassDirect &other);
bool operator != (const FFTRealPassDirect &other);

}; // class FFTRealPassDirect



} // namespace ffft



#include "ffft/FFTRealPassDirect.hpp"



#endif // ffft_FFTRealPassDirect_HEADER_INCLUDED



/*\\\ EOF \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/

+ 205
- 0
ports/refine/source/ffft/FFTRealPassDirect.hpp View File

@@ -0,0 +1,205 @@
/*****************************************************************************

FFTRealPassDirect.hpp
By Laurent de Soras

--- Legal stuff ---

This program is free software. It comes without any warranty, to
the extent permitted by applicable law. You can redistribute it
and/or modify it under the terms of the Do What The Fuck You Want
To Public License, Version 2, as published by Sam Hocevar. See
http://sam.zoy.org/wtfpl/COPYING for more details.

*Tab=3***********************************************************************/



#if defined (ffft_FFTRealPassDirect_CURRENT_CODEHEADER)
#error Recursive inclusion of FFTRealPassDirect code header.
#endif
#define ffft_FFTRealPassDirect_CURRENT_CODEHEADER

#if ! defined (ffft_FFTRealPassDirect_CODEHEADER_INCLUDED)
#define ffft_FFTRealPassDirect_CODEHEADER_INCLUDED



/*\\\ INCLUDE FILES \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/

#include "ffft/FFTRealUseTrigo.h"



namespace ffft
{



/*\\\ PUBLIC \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/



template <>
inline void FFTRealPassDirect <1>::process (long len, DataType dest_ptr [], DataType src_ptr [], const DataType x_ptr [], const DataType cos_ptr [], long cos_len, const long br_ptr [], OscType osc_list [])
{
// First and second pass at once
const long qlen = len >> 2;

long coef_index = 0;
do
{
// To do: unroll the loop (2x).
const long ri_0 = br_ptr [coef_index >> 2];
const long ri_1 = ri_0 + 2 * qlen; // bit_rev_lut_ptr [coef_index + 1];
const long ri_2 = ri_0 + 1 * qlen; // bit_rev_lut_ptr [coef_index + 2];
const long ri_3 = ri_0 + 3 * qlen; // bit_rev_lut_ptr [coef_index + 3];

DataType * const df2 = dest_ptr + coef_index;
df2 [1] = x_ptr [ri_0] - x_ptr [ri_1];
df2 [3] = x_ptr [ri_2] - x_ptr [ri_3];

const DataType sf_0 = x_ptr [ri_0] + x_ptr [ri_1];
const DataType sf_2 = x_ptr [ri_2] + x_ptr [ri_3];

df2 [0] = sf_0 + sf_2;
df2 [2] = sf_0 - sf_2;

coef_index += 4;
}
while (coef_index < len);
}

template <>
inline void FFTRealPassDirect <2>::process (long len, DataType dest_ptr [], DataType src_ptr [], const DataType x_ptr [], const DataType cos_ptr [], long cos_len, const long br_ptr [], OscType osc_list [])
{
// Executes "previous" passes first. Inverts source and destination buffers
FFTRealPassDirect <1>::process (
len,
src_ptr,
dest_ptr,
x_ptr,
cos_ptr,
cos_len,
br_ptr,
osc_list
);

// Third pass
const DataType sqrt2_2 = DataType (SQRT2 * 0.5);

long coef_index = 0;
do
{
dest_ptr [coef_index ] = src_ptr [coef_index] + src_ptr [coef_index + 4];
dest_ptr [coef_index + 4] = src_ptr [coef_index] - src_ptr [coef_index + 4];
dest_ptr [coef_index + 2] = src_ptr [coef_index + 2];
dest_ptr [coef_index + 6] = src_ptr [coef_index + 6];

DataType v;

v = (src_ptr [coef_index + 5] - src_ptr [coef_index + 7]) * sqrt2_2;
dest_ptr [coef_index + 1] = src_ptr [coef_index + 1] + v;
dest_ptr [coef_index + 3] = src_ptr [coef_index + 1] - v;

v = (src_ptr [coef_index + 5] + src_ptr [coef_index + 7]) * sqrt2_2;
dest_ptr [coef_index + 5] = v + src_ptr [coef_index + 3];
dest_ptr [coef_index + 7] = v - src_ptr [coef_index + 3];

coef_index += 8;
}
while (coef_index < len);
}

template <int PASS>
void FFTRealPassDirect <PASS>::process (long len, DataType dest_ptr [], DataType src_ptr [], const DataType x_ptr [], const DataType cos_ptr [], long cos_len, const long br_ptr [], OscType osc_list [])
{
// Executes "previous" passes first. Inverts source and destination buffers
FFTRealPassDirect <PASS - 1>::process (
len,
src_ptr,
dest_ptr,
x_ptr,
cos_ptr,
cos_len,
br_ptr,
osc_list
);

const long dist = 1L << (PASS - 1);
const long c1_r = 0;
const long c1_i = dist;
const long c2_r = dist * 2;
const long c2_i = dist * 3;
const long cend = dist * 4;
const long table_step = cos_len >> (PASS - 1);

enum { TRIGO_OSC = PASS - FFTRealFixLenParam::TRIGO_BD_LIMIT };
enum { TRIGO_DIRECT = (TRIGO_OSC >= 0) ? 1 : 0 };

long coef_index = 0;
do
{
const DataType * const sf = src_ptr + coef_index;
DataType * const df = dest_ptr + coef_index;

// Extreme coefficients are always real
df [c1_r] = sf [c1_r] + sf [c2_r];
df [c2_r] = sf [c1_r] - sf [c2_r];
df [c1_i] = sf [c1_i];
df [c2_i] = sf [c2_i];

FFTRealUseTrigo <TRIGO_DIRECT>::prepare (osc_list [TRIGO_OSC]);

// Others are conjugate complex numbers
for (long i = 1; i < dist; ++ i)
{
DataType c;
DataType s;
FFTRealUseTrigo <TRIGO_DIRECT>::iterate (
osc_list [TRIGO_OSC],
c,
s,
cos_ptr,
i * table_step,
(dist - i) * table_step
);

const DataType sf_r_i = sf [c1_r + i];
const DataType sf_i_i = sf [c1_i + i];

const DataType v1 = sf [c2_r + i] * c - sf [c2_i + i] * s;
df [c1_r + i] = sf_r_i + v1;
df [c2_r - i] = sf_r_i - v1;

const DataType v2 = sf [c2_r + i] * s + sf [c2_i + i] * c;
df [c2_r + i] = v2 + sf_i_i;
df [cend - i] = v2 - sf_i_i;
}

coef_index += cend;
}
while (coef_index < len);
}



/*\\\ PROTECTED \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/



/*\\\ PRIVATE \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/



} // namespace ffft



#endif // ffft_FFTRealPassDirect_CODEHEADER_INCLUDED

#undef ffft_FFTRealPassDirect_CURRENT_CODEHEADER



/*\\\ EOF \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/

+ 101
- 0
ports/refine/source/ffft/FFTRealPassInverse.h View File

@@ -0,0 +1,101 @@
/*****************************************************************************

FFTRealPassInverse.h
By Laurent de Soras

--- Legal stuff ---

This program is free software. It comes without any warranty, to
the extent permitted by applicable law. You can redistribute it
and/or modify it under the terms of the Do What The Fuck You Want
To Public License, Version 2, as published by Sam Hocevar. See
http://sam.zoy.org/wtfpl/COPYING for more details.

*Tab=3***********************************************************************/



#if ! defined (ffft_FFTRealPassInverse_HEADER_INCLUDED)
#define ffft_FFTRealPassInverse_HEADER_INCLUDED

#if defined (_MSC_VER)
#pragma once
#pragma warning (4 : 4250) // "Inherits via dominance."
#endif



/*\\\ INCLUDE FILES \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/

#include "ffft/def.h"
#include "ffft/FFTRealFixLenParam.h"
#include "ffft/OscSinCos.h"




namespace ffft
{



template <int PASS>
class FFTRealPassInverse
{

/*\\\ PUBLIC \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/

public:

typedef FFTRealFixLenParam::DataType DataType;
typedef OscSinCos <DataType> OscType;

ffft_FORCEINLINE static void
process (long len, DataType dest_ptr [], DataType src_ptr [], const DataType f_ptr [], const DataType cos_ptr [], long cos_len, const long br_ptr [], OscType osc_list []);
ffft_FORCEINLINE static void
process_rec (long len, DataType dest_ptr [], DataType src_ptr [], const DataType cos_ptr [], long cos_len, const long br_ptr [], OscType osc_list []);
ffft_FORCEINLINE static void
process_internal (long len, DataType dest_ptr [], const DataType src_ptr [], const DataType cos_ptr [], long cos_len, const long br_ptr [], OscType osc_list []);



/*\\\ PROTECTED \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/

protected:



/*\\\ PRIVATE \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/

private:



/*\\\ FORBIDDEN MEMBER FUNCTIONS \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/

private:

FFTRealPassInverse ();
FFTRealPassInverse (const FFTRealPassInverse &other);
FFTRealPassInverse &
operator = (const FFTRealPassInverse &other);
bool operator == (const FFTRealPassInverse &other);
bool operator != (const FFTRealPassInverse &other);

}; // class FFTRealPassInverse



} // namespace ffft



#include "ffft/FFTRealPassInverse.hpp"



#endif // ffft_FFTRealPassInverse_HEADER_INCLUDED



/*\\\ EOF \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/

+ 230
- 0
ports/refine/source/ffft/FFTRealPassInverse.hpp View File

@@ -0,0 +1,230 @@
/*****************************************************************************

FFTRealPassInverse.hpp
By Laurent de Soras

--- Legal stuff ---

This program is free software. It comes without any warranty, to
the extent permitted by applicable law. You can redistribute it
and/or modify it under the terms of the Do What The Fuck You Want
To Public License, Version 2, as published by Sam Hocevar. See
http://sam.zoy.org/wtfpl/COPYING for more details.

*Tab=3***********************************************************************/



#if defined (ffft_FFTRealPassInverse_CURRENT_CODEHEADER)
#error Recursive inclusion of FFTRealPassInverse code header.
#endif
#define ffft_FFTRealPassInverse_CURRENT_CODEHEADER

#if ! defined (ffft_FFTRealPassInverse_CODEHEADER_INCLUDED)
#define ffft_FFTRealPassInverse_CODEHEADER_INCLUDED



/*\\\ INCLUDE FILES \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/

#include "ffft/FFTRealUseTrigo.h"



namespace ffft
{



/*\\\ PUBLIC \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/



template <int PASS>
void FFTRealPassInverse <PASS>::process (long len, DataType dest_ptr [], DataType src_ptr [], const DataType f_ptr [], const DataType cos_ptr [], long cos_len, const long br_ptr [], OscType osc_list [])
{
process_internal (
len,
dest_ptr,
f_ptr,
cos_ptr,
cos_len,
br_ptr,
osc_list
);
FFTRealPassInverse <PASS - 1>::process_rec (
len,
src_ptr,
dest_ptr,
cos_ptr,
cos_len,
br_ptr,
osc_list
);
}



template <int PASS>
void FFTRealPassInverse <PASS>::process_rec (long len, DataType dest_ptr [], DataType src_ptr [], const DataType cos_ptr [], long cos_len, const long br_ptr [], OscType osc_list [])
{
process_internal (
len,
dest_ptr,
src_ptr,
cos_ptr,
cos_len,
br_ptr,
osc_list
);
FFTRealPassInverse <PASS - 1>::process_rec (
len,
src_ptr,
dest_ptr,
cos_ptr,
cos_len,
br_ptr,
osc_list
);
}

template <>
inline void FFTRealPassInverse <0>::process_rec (long len, DataType dest_ptr [], DataType src_ptr [], const DataType cos_ptr [], long cos_len, const long br_ptr [], OscType osc_list [])
{
// Stops recursion
}



template <int PASS>
void FFTRealPassInverse <PASS>::process_internal (long len, DataType dest_ptr [], const DataType src_ptr [], const DataType cos_ptr [], long cos_len, const long br_ptr [], OscType osc_list [])
{
const long dist = 1L << (PASS - 1);
const long c1_r = 0;
const long c1_i = dist;
const long c2_r = dist * 2;
const long c2_i = dist * 3;
const long cend = dist * 4;
const long table_step = cos_len >> (PASS - 1);

enum { TRIGO_OSC = PASS - FFTRealFixLenParam::TRIGO_BD_LIMIT };
enum { TRIGO_DIRECT = (TRIGO_OSC >= 0) ? 1 : 0 };

long coef_index = 0;
do
{
const DataType * const sf = src_ptr + coef_index;
DataType * const df = dest_ptr + coef_index;

// Extreme coefficients are always real
df [c1_r] = sf [c1_r] + sf [c2_r];
df [c2_r] = sf [c1_r] - sf [c2_r];
df [c1_i] = sf [c1_i] * 2;
df [c2_i] = sf [c2_i] * 2;

FFTRealUseTrigo <TRIGO_DIRECT>::prepare (osc_list [TRIGO_OSC]);

// Others are conjugate complex numbers
for (long i = 1; i < dist; ++ i)
{
df [c1_r + i] = sf [c1_r + i] + sf [c2_r - i];
df [c1_i + i] = sf [c2_r + i] - sf [cend - i];

DataType c;
DataType s;
FFTRealUseTrigo <TRIGO_DIRECT>::iterate (
osc_list [TRIGO_OSC],
c,
s,
cos_ptr,
i * table_step,
(dist - i) * table_step
);

const DataType vr = sf [c1_r + i] - sf [c2_r - i];
const DataType vi = sf [c2_r + i] + sf [cend - i];

df [c2_r + i] = vr * c + vi * s;
df [c2_i + i] = vi * c - vr * s;
}

coef_index += cend;
}
while (coef_index < len);
}

template <>
inline void FFTRealPassInverse <2>::process_internal (long len, DataType dest_ptr [], const DataType src_ptr [], const DataType cos_ptr [], long cos_len, const long br_ptr [], OscType osc_list [])
{
// Antepenultimate pass
const DataType sqrt2_2 = DataType (SQRT2 * 0.5);

long coef_index = 0;
do
{
dest_ptr [coef_index ] = src_ptr [coef_index] + src_ptr [coef_index + 4];
dest_ptr [coef_index + 4] = src_ptr [coef_index] - src_ptr [coef_index + 4];
dest_ptr [coef_index + 2] = src_ptr [coef_index + 2] * 2;
dest_ptr [coef_index + 6] = src_ptr [coef_index + 6] * 2;

dest_ptr [coef_index + 1] = src_ptr [coef_index + 1] + src_ptr [coef_index + 3];
dest_ptr [coef_index + 3] = src_ptr [coef_index + 5] - src_ptr [coef_index + 7];

const DataType vr = src_ptr [coef_index + 1] - src_ptr [coef_index + 3];
const DataType vi = src_ptr [coef_index + 5] + src_ptr [coef_index + 7];

dest_ptr [coef_index + 5] = (vr + vi) * sqrt2_2;
dest_ptr [coef_index + 7] = (vi - vr) * sqrt2_2;

coef_index += 8;
}
while (coef_index < len);
}

template <>
inline void FFTRealPassInverse <1>::process_internal (long len, DataType dest_ptr [], const DataType src_ptr [], const DataType cos_ptr [], long cos_len, const long br_ptr [], OscType osc_list [])
{
// Penultimate and last pass at once
const long qlen = len >> 2;

long coef_index = 0;
do
{
const long ri_0 = br_ptr [coef_index >> 2];

const DataType b_0 = src_ptr [coef_index ] + src_ptr [coef_index + 2];
const DataType b_2 = src_ptr [coef_index ] - src_ptr [coef_index + 2];
const DataType b_1 = src_ptr [coef_index + 1] * 2;
const DataType b_3 = src_ptr [coef_index + 3] * 2;

dest_ptr [ri_0 ] = b_0 + b_1;
dest_ptr [ri_0 + 2 * qlen] = b_0 - b_1;
dest_ptr [ri_0 + 1 * qlen] = b_2 + b_3;
dest_ptr [ri_0 + 3 * qlen] = b_2 - b_3;

coef_index += 4;
}
while (coef_index < len);
}



/*\\\ PROTECTED \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/



/*\\\ PRIVATE \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/



} // namespace ffft



#endif // ffft_FFTRealPassInverse_CODEHEADER_INCLUDED

#undef ffft_FFTRealPassInverse_CURRENT_CODEHEADER



/*\\\ EOF \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/

+ 78
- 0
ports/refine/source/ffft/FFTRealSelect.h View File

@@ -0,0 +1,78 @@
/*****************************************************************************

FFTRealSelect.h
By Laurent de Soras

--- Legal stuff ---

This program is free software. It comes without any warranty, to
the extent permitted by applicable law. You can redistribute it
and/or modify it under the terms of the Do What The Fuck You Want
To Public License, Version 2, as published by Sam Hocevar. See
http://sam.zoy.org/wtfpl/COPYING for more details.

*Tab=3***********************************************************************/



#if ! defined (ffft_FFTRealSelect_HEADER_INCLUDED)
#define ffft_FFTRealSelect_HEADER_INCLUDED

#if defined (_MSC_VER)
#pragma once
#endif



/*\\\ INCLUDE FILES \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/

#include "ffft/def.h"



namespace ffft
{



template <int P>
class FFTRealSelect
{

/*\\\ PUBLIC \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/

public:

ffft_FORCEINLINE static float *
sel_bin (float *e_ptr, float *o_ptr);



/*\\\ FORBIDDEN MEMBER FUNCTIONS \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/

private:

FFTRealSelect ();
~FFTRealSelect ();
FFTRealSelect (const FFTRealSelect &other);
FFTRealSelect& operator = (const FFTRealSelect &other);
bool operator == (const FFTRealSelect &other);
bool operator != (const FFTRealSelect &other);

}; // class FFTRealSelect



} // namespace ffft



#include "ffft/FFTRealSelect.hpp"



#endif // ffft_FFTRealSelect_HEADER_INCLUDED



/*\\\ EOF \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/

+ 63
- 0
ports/refine/source/ffft/FFTRealSelect.hpp View File

@@ -0,0 +1,63 @@
/*****************************************************************************

FFTRealSelect.hpp
By Laurent de Soras

--- Legal stuff ---

This program is free software. It comes without any warranty, to
the extent permitted by applicable law. You can redistribute it
and/or modify it under the terms of the Do What The Fuck You Want
To Public License, Version 2, as published by Sam Hocevar. See
http://sam.zoy.org/wtfpl/COPYING for more details.

*Tab=3***********************************************************************/



#if defined (ffft_FFTRealSelect_CURRENT_CODEHEADER)
#error Recursive inclusion of FFTRealSelect code header.
#endif
#define ffft_FFTRealSelect_CURRENT_CODEHEADER

#if ! defined (ffft_FFTRealSelect_CODEHEADER_INCLUDED)
#define ffft_FFTRealSelect_CODEHEADER_INCLUDED



namespace ffft
{



/*\\\ PUBLIC \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/



template <int P>
float * FFTRealSelect <P>::sel_bin (float *e_ptr, float *o_ptr)
{
return (o_ptr);
}



template <>
inline float * FFTRealSelect <0>::sel_bin (float *e_ptr, float *o_ptr)
{
return (e_ptr);
}



} // namespace ffft



#endif // ffft_FFTRealSelect_CODEHEADER_INCLUDED

#undef ffft_FFTRealSelect_CURRENT_CODEHEADER



/*\\\ EOF \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/

+ 99
- 0
ports/refine/source/ffft/FFTRealUseTrigo.h View File

@@ -0,0 +1,99 @@
/*****************************************************************************

FFTRealUseTrigo.h
By Laurent de Soras

--- Legal stuff ---

This program is free software. It comes without any warranty, to
the extent permitted by applicable law. You can redistribute it
and/or modify it under the terms of the Do What The Fuck You Want
To Public License, Version 2, as published by Sam Hocevar. See
http://sam.zoy.org/wtfpl/COPYING for more details.

*Tab=3***********************************************************************/



#if ! defined (ffft_FFTRealUseTrigo_HEADER_INCLUDED)
#define ffft_FFTRealUseTrigo_HEADER_INCLUDED

#if defined (_MSC_VER)
#pragma once
#pragma warning (4 : 4250) // "Inherits via dominance."
#endif



/*\\\ INCLUDE FILES \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/

#include "ffft/def.h"
#include "ffft/FFTRealFixLenParam.h"
#include "ffft/OscSinCos.h"



namespace ffft
{



template <int ALGO>
class FFTRealUseTrigo
{

/*\\\ PUBLIC \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/

public:

typedef FFTRealFixLenParam::DataType DataType;
typedef OscSinCos <DataType> OscType;

ffft_FORCEINLINE static void
prepare (OscType &osc);
ffft_FORCEINLINE static void
iterate (OscType &osc, DataType &c, DataType &s, const DataType cos_ptr [], long index_c, long index_s);



/*\\\ PROTECTED \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/

protected:



/*\\\ PRIVATE \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/

private:



/*\\\ FORBIDDEN MEMBER FUNCTIONS \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/

private:

FFTRealUseTrigo ();
~FFTRealUseTrigo ();
FFTRealUseTrigo (const FFTRealUseTrigo &other);
FFTRealUseTrigo &
operator = (const FFTRealUseTrigo &other);
bool operator == (const FFTRealUseTrigo &other);
bool operator != (const FFTRealUseTrigo &other);

}; // class FFTRealUseTrigo



} // namespace ffft



#include "ffft/FFTRealUseTrigo.hpp"



#endif // ffft_FFTRealUseTrigo_HEADER_INCLUDED



/*\\\ EOF \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/

+ 92
- 0
ports/refine/source/ffft/FFTRealUseTrigo.hpp View File

@@ -0,0 +1,92 @@
/*****************************************************************************

FFTRealUseTrigo.hpp
By Laurent de Soras

--- Legal stuff ---

This program is free software. It comes without any warranty, to
the extent permitted by applicable law. You can redistribute it
and/or modify it under the terms of the Do What The Fuck You Want
To Public License, Version 2, as published by Sam Hocevar. See
http://sam.zoy.org/wtfpl/COPYING for more details.

*Tab=3***********************************************************************/



#if defined (ffft_FFTRealUseTrigo_CURRENT_CODEHEADER)
#error Recursive inclusion of FFTRealUseTrigo code header.
#endif
#define ffft_FFTRealUseTrigo_CURRENT_CODEHEADER

#if ! defined (ffft_FFTRealUseTrigo_CODEHEADER_INCLUDED)
#define ffft_FFTRealUseTrigo_CODEHEADER_INCLUDED



/*\\\ INCLUDE FILES \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/

#include "ffft/OscSinCos.h"



namespace ffft
{



/*\\\ PUBLIC \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/



template <int ALGO>
void FFTRealUseTrigo <ALGO>::prepare (OscType &osc)
{
osc.clear_buffers ();
}

template <>
inline void FFTRealUseTrigo <0>::prepare (OscType &osc)
{
// Nothing
}



template <int ALGO>
void FFTRealUseTrigo <ALGO>::iterate (OscType &osc, DataType &c, DataType &s, const DataType cos_ptr [], long index_c, long index_s)
{
osc.step ();
c = osc.get_cos ();
s = osc.get_sin ();
}

template <>
inline void FFTRealUseTrigo <0>::iterate (OscType &osc, DataType &c, DataType &s, const DataType cos_ptr [], long index_c, long index_s)
{
c = cos_ptr [index_c];
s = cos_ptr [index_s];
}



/*\\\ PROTECTED \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/



/*\\\ PRIVATE \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/



} // namespace ffft



#endif // ffft_FFTRealUseTrigo_CODEHEADER_INCLUDED

#undef ffft_FFTRealUseTrigo_CURRENT_CODEHEADER



/*\\\ EOF \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/

+ 107
- 0
ports/refine/source/ffft/OscSinCos.h View File

@@ -0,0 +1,107 @@
/*****************************************************************************

OscSinCos.h
By Laurent de Soras

--- Legal stuff ---

This program is free software. It comes without any warranty, to
the extent permitted by applicable law. You can redistribute it
and/or modify it under the terms of the Do What The Fuck You Want
To Public License, Version 2, as published by Sam Hocevar. See
http://sam.zoy.org/wtfpl/COPYING for more details.

*Tab=3***********************************************************************/



#if ! defined (ffft_OscSinCos_HEADER_INCLUDED)
#define ffft_OscSinCos_HEADER_INCLUDED

#if defined (_MSC_VER)
#pragma once
#pragma warning (4 : 4250) // "Inherits via dominance."
#endif



/*\\\ INCLUDE FILES \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/

#include "def.h"



namespace ffft
{



template <class T>
class OscSinCos
{

/*\\\ PUBLIC \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/

public:

typedef T DataType;

OscSinCos ();

ffft_FORCEINLINE void
set_step (double angle_rad);

ffft_FORCEINLINE DataType
get_cos () const;
ffft_FORCEINLINE DataType
get_sin () const;
ffft_FORCEINLINE void
step ();
ffft_FORCEINLINE void
clear_buffers ();



/*\\\ PROTECTED \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/

protected:



/*\\\ PRIVATE \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/

private:

DataType _pos_cos; // Current phase expressed with sin and cos. [-1 ; 1]
DataType _pos_sin; // -
DataType _step_cos; // Phase increment per step, [-1 ; 1]
DataType _step_sin; // -



/*\\\ FORBIDDEN MEMBER FUNCTIONS \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/

private:

OscSinCos (const OscSinCos &other);
OscSinCos & operator = (const OscSinCos &other);
bool operator == (const OscSinCos &other);
bool operator != (const OscSinCos &other);

}; // class OscSinCos



} // namespace ffft



#include "OscSinCos.hpp"



#endif // ffft_OscSinCos_HEADER_INCLUDED



/*\\\ EOF \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/

+ 123
- 0
ports/refine/source/ffft/OscSinCos.hpp View File

@@ -0,0 +1,123 @@
/*****************************************************************************

OscSinCos.hpp
By Laurent de Soras

--- Legal stuff ---

This program is free software. It comes without any warranty, to
the extent permitted by applicable law. You can redistribute it
and/or modify it under the terms of the Do What The Fuck You Want
To Public License, Version 2, as published by Sam Hocevar. See
http://sam.zoy.org/wtfpl/COPYING for more details.

*Tab=3***********************************************************************/



#if defined (ffft_OscSinCos_CURRENT_CODEHEADER)
#error Recursive inclusion of OscSinCos code header.
#endif
#define ffft_OscSinCos_CURRENT_CODEHEADER

#if ! defined (ffft_OscSinCos_CODEHEADER_INCLUDED)
#define ffft_OscSinCos_CODEHEADER_INCLUDED



/*\\\ INCLUDE FILES \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/

#include <cmath>

namespace std { }



namespace ffft
{



/*\\\ PUBLIC \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/



template <class T>
OscSinCos <T>::OscSinCos ()
: _pos_cos (1)
, _pos_sin (0)
, _step_cos (1)
, _step_sin (0)
{
// Nothing
}



template <class T>
void OscSinCos <T>::set_step (double angle_rad)
{
using namespace std;

_step_cos = static_cast <DataType> (cos (angle_rad));
_step_sin = static_cast <DataType> (sin (angle_rad));
}



template <class T>
typename OscSinCos <T>::DataType OscSinCos <T>::get_cos () const
{
return (_pos_cos);
}



template <class T>
typename OscSinCos <T>::DataType OscSinCos <T>::get_sin () const
{
return (_pos_sin);
}



template <class T>
void OscSinCos <T>::step ()
{
const DataType old_cos = _pos_cos;
const DataType old_sin = _pos_sin;

_pos_cos = old_cos * _step_cos - old_sin * _step_sin;
_pos_sin = old_cos * _step_sin + old_sin * _step_cos;
}



template <class T>
void OscSinCos <T>::clear_buffers ()
{
_pos_cos = static_cast <DataType> (1);
_pos_sin = static_cast <DataType> (0);
}



/*\\\ PROTECTED \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/



/*\\\ PRIVATE \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/



} // namespace ffft



#endif // ffft_OscSinCos_CODEHEADER_INCLUDED

#undef ffft_OscSinCos_CURRENT_CODEHEADER



/*\\\ EOF \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/

+ 60
- 0
ports/refine/source/ffft/def.h View File

@@ -0,0 +1,60 @@
/*****************************************************************************

def.h
By Laurent de Soras

--- Legal stuff ---

This program is free software. It comes without any warranty, to
the extent permitted by applicable law. You can redistribute it
and/or modify it under the terms of the Do What The Fuck You Want
To Public License, Version 2, as published by Sam Hocevar. See
http://sam.zoy.org/wtfpl/COPYING for more details.

*Tab=3***********************************************************************/



#if ! defined (ffft_def_HEADER_INCLUDED)
#define ffft_def_HEADER_INCLUDED

#if defined (_MSC_VER)
#pragma once
#pragma warning (4 : 4250) // "Inherits via dominance."
#endif



/*\\\ INCLUDE FILES \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/



namespace ffft
{



const double PI = 3.1415926535897932384626433832795;
const double SQRT2 = 1.41421356237309514547462185873883;

#if defined (_MSC_VER)

#define ffft_FORCEINLINE __forceinline

#else

#define ffft_FORCEINLINE inline

#endif



} // namespace ffft



#endif // ffft_def_HEADER_INCLUDED



/*\\\ EOF \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/

+ 293
- 0
ports/refine/source/ffft/readme.txt View File

@@ -0,0 +1,293 @@
==============================================================================

FFTReal
Version 2.11

Fourier transformation (FFT, IFFT) library specialised for real data
Portable ISO C++

Copyright (c) 1999-2010 Laurent de Soras
Object Pascal port (c) Frederic Vanmol

==============================================================================



Contents:

1. Legal
2. Content
3. Using FFTReal
3.1 FFTReal - Length fixed at run-time
3.2 FFTRealFixLen - Length fixed at compile-time
3.3 Data organisation
4. Compilation and testing
5. History
6. Contact



1. Legal
--------

FFTReal is distributed under the terms of the Do What The Fuck You Want To
Public License.

Check the file license.txt to get full information about the license.



2. Content
----------

FFTReal is a library to compute Discrete Fourier Transforms (DFT) with the
FFT algorithm (Fast Fourier Transform) on arrays of real numbers. It can
also compute the inverse transform.

You should find in this package a lot of files ; some of them are of
particular interest:
- readme.txt : you are reading it
- ffft/FFTReal.h : FFT, length fixed at run-time
- ffft/FFTRealFixLen.h: FFT, length fixed at compile-time
- delphi/FFTReal.pas : Pascal implementation (working but not up-to-date)



3. Using FFTReal
----------------

Important - if you were using older versions of FFTReal (up to 1.03), some
things have changed. FFTReal is now a template. Therefore use FFTReal<float>
or FFTReal<double> in your code depending on the application datatype. The
flt_t typedef has been removed. And if you were previously using FFTReal 2.0,
note that all the classes have moved to the ffft namespace.

You have two ways to use FFTReal. In the first way, the FFT has its length
fixed at run-time, when the object is instanciated. It means that you have
not to know the length when you write the code. This is the usual way of
proceeding.


3.1 FFTReal - Length fixed at run-time
--------------------------------------

Just instanciate one time a FFTReal object. Specify the data type you want
as template parameter (only floating point: float, double, long double or
custom type). The constructor precompute a lot of things, so it may be a bit
long. The parameter is the number of points used for the next FFTs. It must
be a power of 2:

#include "ffft/FFTReal.h"
...
long len = 1024;
...
// 1024-point FFT object constructed.
ffft::FFTReal <float> fft_object (len);

Then you can use this object to compute as many FFTs and IFFTs as you want.
They will be computed very quickly because a lot of work has been done in the
object construction.

float x [1024];
float f [1024];

...
fft_object.do_fft (f, x); // x (real) --FFT---> f (complex)
...
fft_object.do_ifft (f, x); // f (complex) --IFFT--> x (real)
fft_object.rescale (x); // Post-scaling should be done after FFT+IFFT
...

x [] and f [] are floating point number arrays. x [] is the real number
sequence which we want to compute the FFT. f [] is the result, in the
"frequency" domain. f has the same number of elements as x [], but f []
elements are complex numbers. The routine uses some FFT properties to
optimize memory and to reduce calculations: the transformaton of a real
number sequence is a conjugate complex number sequence: F [k] = F [-k]*.


3.2 FFTRealFixLen - Length fixed at compile-time
------------------------------------------------

This class is significantly faster than the previous one, giving a speed
gain between 50 and 100 %. The template parameter is the base-2 logarithm of
the FFT length. The datatype is float; it can be changed by modifying the
DataType typedef in FFTRealFixLenParam.h. As FFTReal class, it supports
only floating-point types or equivalent.

Use is similar as the one of FFTReal. To instanciate the object, just proceed
as indicated below:

#include "ffft/FFTRealFixLen.h"
...
// 1024-point (2^10) FFT object constructed.
ffft::FFTRealFixLen <10> fft_object;

Warning: long FFT objects may take a very long time to compile, depending on
the compiler and its optimisation options. If compilation time is too high,
encapsulate the FFT object in a seprate class whose header doesn't need
to include FFTRealFixLen.h, so you just have to compile the wrapper once
and only link it the other times. For example (quick, dirty and incomplete):

ffft/FFTWrapper.h: | ffft/FFTWrapper.cpp:
|
class FFTWrapper | #include "ffft/FFTRealFixLen.h"
{ | #include "ffft/FFTWrapper.h"
public: |
FFTWrapper (); | FFTWrapper::FFTWrapper ()
~FFTWrapper (); | : _impl_ptr ((void*) new FTRealFixLen <10>)
void do_fft (...); | {
void do_ifft (...); | }
private: |
void *_impl_ptr; | ...
} |


3.3 Data organisation
---------------------

Mathematically speaking, DFT formulas below show what does FFTReal:

do_fft() : f(k) = sum (p = 0, N-1, x(p) * exp (+j*2*pi*k*p/N))
do_ifft(): x(k) = sum (p = 0, N-1, f(p) * exp (-j*2*pi*k*p/N))

Where j is the square root of -1. The formulas differ only by the sign of
the exponential. When the sign is positive, the transform is called positive.
Common formulas for Fourier transform are negative for the direct tranform and
positive for the inverse one.

However in these formulas, f is an array of complex numbers and doesn't
correspound exactly to the f[] array taken as function parameter. The
following table shows how the f[] sequence is mapped onto the usable FFT
coefficients (called bins):

FFTReal output | Positive FFT equiv. | Negative FFT equiv.
---------------+-----------------------+-----------------------
f [0] | Real (bin 0) | Real (bin 0)
f [...] | Real (bin ...) | Real (bin ...)
f [length/2] | Real (bin length/2) | Real (bin length/2)
f [length/2+1] | Imag (bin 1) | -Imag (bin 1)
f [...] | Imag (bin ...) | -Imag (bin ...)
f [length-1] | Imag (bin length/2-1) | -Imag (bin length/2-1)

And FFT bins are distributed in f [] as above:

| | Positive FFT | Negative FFT
Bin | Real part | imaginary part | imaginary part
------------+----------------+-----------------+---------------
0 | f [0] | 0 | 0
1 | f [1] | f [length/2+1] | -f [length/2+1]
... | f [...], | f [...] | -f [...]
length/2-1 | f [length/2-1] | f [length-1] | -f [length-1]
length/2 | f [length/2] | 0 | 0
length/2+1 | f [length/2-1] | -f [length-1] | f [length-1]
... | f [...] | -f [...] | f [...]
length-1 | f [1] | -f [length/2+1] | f [length/2+1]

f [] coefficients have the same layout for FFT and IFFT functions. You may
notice that scaling must be done if you want to retrieve x after FFT and IFFT.
Actually, IFFT (FFT (x)) = x * length(x). This is a not a problem because
most of the applications don't care about absolute values. Thus, the operation
requires less calculation. If you want to use the FFT and IFFT to transform a
signal, you have to apply post- (or pre-) processing yourself. Multiplying
or dividing floating point numbers by a power of 2 doesn't generate extra
computation noise.



4. Compilation and testing
--------------------------

Drop the following files into your project or makefile:

ffft/Array.*
ffft/def.h
ffft/DynArray.*
ffft/FFTReal*.h*
ffft/OscSinCos.*

Other files are for testing purpose only, do not include them if you just need
to use the library; they are not needed to use FFTReal in your own programs.

FFTReal may be compiled in two versions: release and debug. Debug version
has checks that could slow down the code. Define NDEBUG to set the Release
mode. For example, the command line to compile the test bench on GCC would
look like:

Debug mode:
g++ -Wall -I. -o ./fftreal_debug.exe ffft/test/*.cpp ffft/test/stopwatch/*.cpp

Release mode:
g++ -Wall -I. -o ./fftreal_release.exe -DNDEBUG -O3 ffft/test/*.cpp ffft/test/stopwatch/*.cpp

It may be tricky to compile the test bench because the speed tests use the
stopwatch sub-library, which is not that cross-platform. If you encounter
any problem that you cannot easily fix while compiling it, edit the file
ffft/test/conf.h and un-define the speed test macro. Remove the stopwatch
directory from your source file list, too.

If it's not done by default, you should activate the exception handling
of your compiler to get the class memory-leak-safe. Thus, when a memory
allocation fails (in the constructor), an exception is thrown and the entire
object is safely destructed. It reduces the permanent error checking overhead
in the client code. Also, the test bench requires Run-Time Type Information
(RTTI) to be enabled in order to display the names of the tested classes -
sometimes mangled, depending on the compiler.

Please note: the test bench may take an insane time to compile, especially in
Release mode, because a lot of recursive templates are instanciated.



5. History
----------

v2.11 (2010.09.12)
- The LGPL was not well suited to 100% template code, therefore I changed
the license again. Everything is released under the WTFPL.
- Removed warnings in the testcode on MSVC++ 8.0
- Fixed the multiple definition linking error with template specialisations
on GCC 4.

v2.10 (2008.05.28)
- Classes are now in the ffft namespace
- Changed directory structure
- Fixed compilation information in the documentation

v2.00 (2005.10.18)
- Turned FFTReal class into template (data type as parameter)
- Added FFTRealFixLen
- Trigonometric tables are size-limited in order to preserve cache memory;
over a given size, sin/cos functions are computed on the fly.
- Better test bench for accuracy and speed
- Changed license to LGPL

v1.03 (2001.06.15)
- Thanks to Frederic Vanmol for the Pascal port (works with Delphi).
- Documentation improvement

v1.02 (2001.03.25)
- sqrt() is now precomputed when the object FFTReal is constructed, resulting
in speed impovement for small size FFT.

v1.01 (2000)
- Small modifications, I don't remember what.

v1.00 (1999.08.14)
- First version released



6. Contact
----------

Please address any comment, bug report or flame to:

Laurent de Soras
laurent.de.soras@free.fr
http://ldesoras.free.fr

For the Pascal port:
Frederic Vanmol
frederic@fruityloops.com


Loading…
Cancel
Save