Bring in Sassy Scope
Signed-off-by: falkTX <falktx@falktx.com>
This commit is contained in:
parent
6cfbf95ffc
commit
f83b483e82
29 changed files with 4901 additions and 0 deletions
|
@ -182,6 +182,15 @@
|
|||
"Visual"
|
||||
]
|
||||
},
|
||||
{
|
||||
"slug": "SassyScope",
|
||||
"name": "Sassy Scope",
|
||||
"description": "Scope from Sassy Audio Spreadsheet",
|
||||
"manualUrl": "https://github.com/DISTRHO/Cardinal/blob/main/docs/CARDINAL-MODULES.md#sassy-scope",
|
||||
"tags": [
|
||||
"Visual"
|
||||
]
|
||||
},
|
||||
{
|
||||
"slug": "TextEditor",
|
||||
"name": "Text Editor",
|
||||
|
|
274
plugins/Cardinal/src/SassyScope.cpp
Normal file
274
plugins/Cardinal/src/SassyScope.cpp
Normal file
|
@ -0,0 +1,274 @@
|
|||
/*
|
||||
* DISTRHO Cardinal Plugin
|
||||
* Copyright (C) 2021-2022 Filipe Coelho <falktx@falktx.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 3 of
|
||||
* the License, or any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* For a full copy of the GNU General Public License see the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "plugincontext.hpp"
|
||||
#include "ImGuiWidget.hpp"
|
||||
#include "sassy/sassy.hpp"
|
||||
#include "sassy/sassy_scope.cpp"
|
||||
|
||||
namespace ffft {
|
||||
template<class DT, int size>
|
||||
class FFTRealWithSize : public FFTReal<DT> {
|
||||
public:
|
||||
explicit FFTRealWithSize() : FFTReal<DT>(size) {}
|
||||
};
|
||||
}
|
||||
|
||||
struct SassyScopeModule : Module {
|
||||
enum ParamIds {
|
||||
NUM_PARAMS
|
||||
};
|
||||
enum InputIds {
|
||||
INPUT1,
|
||||
INPUT2,
|
||||
INPUT3,
|
||||
INPUT4,
|
||||
NUM_INPUTS
|
||||
};
|
||||
enum OutputIds {
|
||||
NUM_OUTPUTS
|
||||
};
|
||||
enum LightIds {
|
||||
NUM_LIGHTS
|
||||
};
|
||||
|
||||
ScopeData scope;
|
||||
|
||||
ffft::FFTRealWithSize<float, 16*2> fftObj16;
|
||||
ffft::FFTRealWithSize<float, 32*2> fftObj32;
|
||||
ffft::FFTRealWithSize<float, 64*2> fftObj64;
|
||||
ffft::FFTRealWithSize<float, 128*2> fftObj128;
|
||||
ffft::FFTRealWithSize<float, 256*2> fftObj256;
|
||||
ffft::FFTRealWithSize<float, 512*2> fftObj512;
|
||||
ffft::FFTRealWithSize<float, 1024*2> fftObj1024;
|
||||
ffft::FFTRealWithSize<float, 2048*2> fftObj2048;
|
||||
ffft::FFTRealWithSize<float, 4096*2> fftObj4096;
|
||||
ffft::FFTRealWithSize<float, 8192*2> fftObj8192;
|
||||
ffft::FFTRealWithSize<float, 16384*2> fftObj16384;
|
||||
ffft::FFTRealWithSize<float, 32768*2> fftObj32768;
|
||||
ffft::FFTRealWithSize<float, 65536*2> fftObj65536;
|
||||
|
||||
SassyScopeModule()
|
||||
{
|
||||
config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS);
|
||||
|
||||
scope.fft.average = 1;
|
||||
scope.fft.obj16 = &fftObj16;
|
||||
scope.fft.obj32 = &fftObj32;
|
||||
scope.fft.obj64 = &fftObj64;
|
||||
scope.fft.obj128 = &fftObj128;
|
||||
scope.fft.obj256 = &fftObj256;
|
||||
scope.fft.obj512 = &fftObj512;
|
||||
scope.fft.obj1024 = &fftObj1024;
|
||||
scope.fft.obj2048 = &fftObj2048;
|
||||
scope.fft.obj4096 = &fftObj4096;
|
||||
scope.fft.obj8192 = &fftObj8192;
|
||||
scope.fft.obj16384 = &fftObj16384;
|
||||
scope.fft.obj32768 = &fftObj32768;
|
||||
scope.fft.obj65536 = &fftObj65536;
|
||||
}
|
||||
|
||||
void process(const ProcessArgs&) override
|
||||
{
|
||||
scope.probe(inputs[INPUT1].getVoltage(),
|
||||
inputs[INPUT2].getVoltage(),
|
||||
inputs[INPUT3].getVoltage(),
|
||||
inputs[INPUT4].getVoltage());
|
||||
}
|
||||
|
||||
void onSampleRateChange(const SampleRateChangeEvent& e) override
|
||||
{
|
||||
scope.realloc(e.sampleRate);
|
||||
}
|
||||
};
|
||||
|
||||
// used for module browser
|
||||
static ScopeData* getFakeScopeInstance()
|
||||
{
|
||||
static ScopeData scope;
|
||||
static ffft::FFTReal<float> fftObj16(16*2);
|
||||
static ffft::FFTReal<float> fftObj32(32*2);
|
||||
static ffft::FFTReal<float> fftObj64(64*2);
|
||||
static ffft::FFTReal<float> fftObj128(128*2);
|
||||
static ffft::FFTReal<float> fftObj256(256*2);
|
||||
static ffft::FFTReal<float> fftObj512(512*2);
|
||||
static ffft::FFTReal<float> fftObj1024(1024*2);
|
||||
static ffft::FFTReal<float> fftObj2048(2048*2);
|
||||
static ffft::FFTReal<float> fftObj4096(4096*2);
|
||||
static ffft::FFTReal<float> fftObj8192(8192*2);
|
||||
static ffft::FFTReal<float> fftObj16384(16384*2);
|
||||
static ffft::FFTReal<float> fftObj32768(32768*2);
|
||||
static ffft::FFTReal<float> fftObj65536(65536*2);
|
||||
|
||||
static bool needsInit = true;
|
||||
|
||||
if (needsInit)
|
||||
{
|
||||
needsInit = false;
|
||||
scope.fft.average = 1;
|
||||
scope.fft.obj16 = &fftObj16;
|
||||
scope.fft.obj32 = &fftObj32;
|
||||
scope.fft.obj64 = &fftObj64;
|
||||
scope.fft.obj128 = &fftObj128;
|
||||
scope.fft.obj256 = &fftObj256;
|
||||
scope.fft.obj512 = &fftObj512;
|
||||
scope.fft.obj1024 = &fftObj1024;
|
||||
scope.fft.obj2048 = &fftObj2048;
|
||||
scope.fft.obj4096 = &fftObj4096;
|
||||
scope.fft.obj8192 = &fftObj8192;
|
||||
scope.fft.obj16384 = &fftObj16384;
|
||||
scope.fft.obj32768 = &fftObj32768;
|
||||
scope.fft.obj65536 = &fftObj65536;
|
||||
scope.realloc(48000);
|
||||
}
|
||||
|
||||
return &scope;
|
||||
}
|
||||
|
||||
struct SassyScopeWidget : ImGuiWidget {
|
||||
SassyScopeModule* module = nullptr;
|
||||
|
||||
void drawImGui() override
|
||||
{
|
||||
const float scaleFactor = getScaleFactor();
|
||||
|
||||
ImGui::SetNextWindowPos(ImVec2(0, 0));
|
||||
ImGui::SetNextWindowSize(ImVec2(box.size.x * scaleFactor, box.size.y * scaleFactor));
|
||||
|
||||
do_show_scope_window(module != nullptr ? &module->scope : getFakeScopeInstance(), scaleFactor);
|
||||
}
|
||||
|
||||
void onButton(const ButtonEvent& e)
|
||||
{
|
||||
// if mouse press is over draggable areas, do nothing so event can go to Rack
|
||||
if (e.action == GLFW_PRESS)
|
||||
{
|
||||
// bottom left
|
||||
if (e.pos.x < 116 && e.pos.y >= 335)
|
||||
return;
|
||||
// bottom right
|
||||
if (e.pos.x >= 456 && e.pos.y >= 348)
|
||||
return;
|
||||
// fft label
|
||||
if (e.pos.x >= 491 && e.pos.y >= 54 && e.pos.y <= 74)
|
||||
return;
|
||||
// nudge label
|
||||
if (e.pos.x >= 463 && e.pos.y >= 236 && e.pos.y <= 255)
|
||||
return;
|
||||
// center scope
|
||||
if (e.pos.x >= 110 && e.pos.x <= 452 && e.pos.y >= 0 && e.pos.y <= 350)
|
||||
return;
|
||||
}
|
||||
|
||||
ImGuiWidget::onButton(e);
|
||||
}
|
||||
};
|
||||
|
||||
struct SassyScopeModuleWidget : ModuleWidget {
|
||||
SassyScopeModule* scopeModule = nullptr;
|
||||
SassyScopeWidget* scopeWidget = nullptr;
|
||||
|
||||
SassyScopeModuleWidget(SassyScopeModule* const module) {
|
||||
setModule(module);
|
||||
box.size = Vec(RACK_GRID_WIDTH * 37, RACK_GRID_HEIGHT);
|
||||
|
||||
scopeModule = module;
|
||||
scopeWidget = new SassyScopeWidget();
|
||||
scopeWidget->box.pos = Vec(0, 0);
|
||||
scopeWidget->box.size = Vec(box.size.x, box.size.y);
|
||||
scopeWidget->module = module;
|
||||
addChild(scopeWidget);
|
||||
|
||||
for (int i=0; i<SassyScopeModule::NUM_INPUTS; ++i)
|
||||
addInput(createInput<PJ301MPort>(Vec(5 + 26.5f * i, RACK_GRID_HEIGHT - 40), module, i));
|
||||
}
|
||||
|
||||
void draw(const DrawArgs& args) override
|
||||
{
|
||||
nvgBeginPath(args.vg);
|
||||
nvgRect(args.vg, 0.0, 0.0, box.size.x, box.size.y);
|
||||
nvgFillColor(args.vg, nvgRGB(0x20, 0x20, 0x20));
|
||||
nvgFill(args.vg);
|
||||
ModuleWidget::draw(args);
|
||||
}
|
||||
|
||||
void step() override
|
||||
{
|
||||
ModuleWidget::step();
|
||||
|
||||
if (scopeModule == nullptr)
|
||||
return;
|
||||
|
||||
// Update colors
|
||||
for (int i=0; i<SassyScopeModule::NUM_INPUTS; ++i)
|
||||
{
|
||||
if (CableWidget* const cableWidget = APP->scene->rack->getTopCable(getInput(i)))
|
||||
{
|
||||
NVGcolor c = cableWidget->color;
|
||||
scopeModule->scope.colors[i] = (clamp(int(c.a * 0xff), 0, 0xff) << 24)
|
||||
| (clamp(int(c.b * 0xff), 0, 0xff) << 16)
|
||||
| (clamp(int(c.g * 0xff), 0, 0xff) << 8)
|
||||
| clamp(int(c.r * 0xff), 0, 0xff);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void appendContextMenu(Menu* const menu) override
|
||||
{
|
||||
menu->addChild(new MenuSeparator);
|
||||
|
||||
struct AveragingItem : MenuItem {
|
||||
ScopeData* scope;
|
||||
Menu* createChildMenu() override {
|
||||
Menu* menu = new Menu;
|
||||
menu->addChild(createCheckMenuItem("1x", "",
|
||||
[=]() {return scope->fft.average == 1;},
|
||||
[=]() {scope->fft.average = 1;}
|
||||
));
|
||||
menu->addChild(createCheckMenuItem("4x", "",
|
||||
[=]() {return scope->fft.average == 4;},
|
||||
[=]() {scope->fft.average = 4;}
|
||||
));
|
||||
menu->addChild(createCheckMenuItem("16x", "",
|
||||
[=]() {return scope->fft.average == 16;},
|
||||
[=]() {scope->fft.average = 16;}
|
||||
));
|
||||
menu->addChild(createCheckMenuItem("64x", "",
|
||||
[=]() {return scope->fft.average == 64;},
|
||||
[=]() {scope->fft.average = 64;}
|
||||
));
|
||||
menu->addChild(createCheckMenuItem("256x", "",
|
||||
[=]() {return scope->fft.average == 256;},
|
||||
[=]() {scope->fft.average = 256;}
|
||||
));
|
||||
return menu;
|
||||
}
|
||||
};
|
||||
AveragingItem* const averagingItem = new AveragingItem;
|
||||
averagingItem->text = "Averaging (FFT mode)";
|
||||
averagingItem->rightText = string::f("%d", scopeModule->scope.fft.average) + " " + RIGHT_ARROW;
|
||||
averagingItem->scope = &scopeModule->scope;
|
||||
menu->addChild(averagingItem);
|
||||
}
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
Model* modelSassyScope = createModel<SassyScopeModule, SassyScopeModuleWidget>("SassyScope");
|
||||
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
|
|
@ -46,6 +46,7 @@ extern Model* modelHostParameters;
|
|||
extern Model* modelHostTime;
|
||||
extern Model* modelIldaeil;
|
||||
extern Model* modelMPV;
|
||||
extern Model* modelSassyScope;
|
||||
extern Model* modelTextEditor;
|
||||
|
||||
extern std::vector<Model*> hostTerminalModels;
|
||||
|
|
98
plugins/Cardinal/src/sassy/fftreal/Array.h
Normal file
98
plugins/Cardinal/src/sassy/fftreal/Array.h
Normal 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 "Array.hpp"
|
||||
|
||||
|
||||
|
||||
#endif // ffft_Array_HEADER_INCLUDED
|
||||
|
||||
|
||||
|
||||
/*\\\ EOF \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/
|
99
plugins/Cardinal/src/sassy/fftreal/Array.hpp
Normal file
99
plugins/Cardinal/src/sassy/fftreal/Array.hpp
Normal 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
plugins/Cardinal/src/sassy/fftreal/DynArray.h
Normal file
101
plugins/Cardinal/src/sassy/fftreal/DynArray.h
Normal 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
plugins/Cardinal/src/sassy/fftreal/DynArray.hpp
Normal file
144
plugins/Cardinal/src/sassy/fftreal/DynArray.hpp
Normal 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 \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/
|
143
plugins/Cardinal/src/sassy/fftreal/FFTReal.h
Normal file
143
plugins/Cardinal/src/sassy/fftreal/FFTReal.h
Normal file
|
@ -0,0 +1,143 @@
|
|||
/*****************************************************************************
|
||||
|
||||
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 \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/
|
917
plugins/Cardinal/src/sassy/fftreal/FFTReal.hpp
Normal file
917
plugins/Cardinal/src/sassy/fftreal/FFTReal.hpp
Normal file
|
@ -0,0 +1,917 @@
|
|||
/*****************************************************************************
|
||||
|
||||
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 ();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
==============================================================================
|
||||
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
plugins/Cardinal/src/sassy/fftreal/FFTRealFixLen.h
Normal file
131
plugins/Cardinal/src/sassy/fftreal/FFTRealFixLen.h
Normal 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 "Array.h"
|
||||
#include "DynArray.h"
|
||||
#include "FFTRealFixLenParam.h"
|
||||
#include "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 "FFTRealFixLen.hpp"
|
||||
|
||||
|
||||
|
||||
#endif // ffft_FFTRealFixLen_HEADER_INCLUDED
|
||||
|
||||
|
||||
|
||||
/*\\\ EOF \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/
|
323
plugins/Cardinal/src/sassy/fftreal/FFTRealFixLen.hpp
Normal file
323
plugins/Cardinal/src/sassy/fftreal/FFTRealFixLen.hpp
Normal 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 "def.h"
|
||||
#include "FFTRealPassDirect.h"
|
||||
#include "FFTRealPassInverse.h"
|
||||
#include "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
plugins/Cardinal/src/sassy/fftreal/FFTRealFixLenParam.h
Normal file
90
plugins/Cardinal/src/sassy/fftreal/FFTRealFixLenParam.h
Normal 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
plugins/Cardinal/src/sassy/fftreal/FFTRealPassDirect.h
Normal file
96
plugins/Cardinal/src/sassy/fftreal/FFTRealPassDirect.h
Normal 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 "def.h"
|
||||
#include "FFTRealFixLenParam.h"
|
||||
#include "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 "FFTRealPassDirect.hpp"
|
||||
|
||||
|
||||
|
||||
#endif // ffft_FFTRealPassDirect_HEADER_INCLUDED
|
||||
|
||||
|
||||
|
||||
/*\\\ EOF \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/
|
205
plugins/Cardinal/src/sassy/fftreal/FFTRealPassDirect.hpp
Normal file
205
plugins/Cardinal/src/sassy/fftreal/FFTRealPassDirect.hpp
Normal 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 "FFTRealUseTrigo.h"
|
||||
|
||||
|
||||
|
||||
namespace ffft
|
||||
{
|
||||
|
||||
|
||||
|
||||
/*\\\ PUBLIC \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/
|
||||
|
||||
|
||||
|
||||
template <>
|
||||
inline void FFTRealPassDirect <1>::process (long len, DataType dest_ptr [], DataType [], const DataType x_ptr [], const DataType [], long , const long br_ptr [], OscType [])
|
||||
{
|
||||
// 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
plugins/Cardinal/src/sassy/fftreal/FFTRealPassInverse.h
Normal file
101
plugins/Cardinal/src/sassy/fftreal/FFTRealPassInverse.h
Normal 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 "def.h"
|
||||
#include "FFTRealFixLenParam.h"
|
||||
#include "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 "FFTRealPassInverse.hpp"
|
||||
|
||||
|
||||
|
||||
#endif // ffft_FFTRealPassInverse_HEADER_INCLUDED
|
||||
|
||||
|
||||
|
||||
/*\\\ EOF \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/
|
230
plugins/Cardinal/src/sassy/fftreal/FFTRealPassInverse.hpp
Normal file
230
plugins/Cardinal/src/sassy/fftreal/FFTRealPassInverse.hpp
Normal 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 "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 , DataType [], DataType [], const DataType [], long , const long [], OscType [])
|
||||
{
|
||||
// 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 [], long , const long [], OscType [])
|
||||
{
|
||||
// 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 [], long , const long br_ptr [], OscType [])
|
||||
{
|
||||
// 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
plugins/Cardinal/src/sassy/fftreal/FFTRealSelect.h
Normal file
78
plugins/Cardinal/src/sassy/fftreal/FFTRealSelect.h
Normal 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 "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 "FFTRealSelect.hpp"
|
||||
|
||||
|
||||
|
||||
#endif // ffft_FFTRealSelect_HEADER_INCLUDED
|
||||
|
||||
|
||||
|
||||
/*\\\ EOF \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/
|
63
plugins/Cardinal/src/sassy/fftreal/FFTRealSelect.hpp
Normal file
63
plugins/Cardinal/src/sassy/fftreal/FFTRealSelect.hpp
Normal 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 *)
|
||||
{
|
||||
return (e_ptr);
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // namespace ffft
|
||||
|
||||
|
||||
|
||||
#endif // ffft_FFTRealSelect_CODEHEADER_INCLUDED
|
||||
|
||||
#undef ffft_FFTRealSelect_CURRENT_CODEHEADER
|
||||
|
||||
|
||||
|
||||
/*\\\ EOF \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/
|
99
plugins/Cardinal/src/sassy/fftreal/FFTRealUseTrigo.h
Normal file
99
plugins/Cardinal/src/sassy/fftreal/FFTRealUseTrigo.h
Normal 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 "def.h"
|
||||
#include "FFTRealFixLenParam.h"
|
||||
#include "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 "FFTRealUseTrigo.hpp"
|
||||
|
||||
|
||||
|
||||
#endif // ffft_FFTRealUseTrigo_HEADER_INCLUDED
|
||||
|
||||
|
||||
|
||||
/*\\\ EOF \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/
|
92
plugins/Cardinal/src/sassy/fftreal/FFTRealUseTrigo.hpp
Normal file
92
plugins/Cardinal/src/sassy/fftreal/FFTRealUseTrigo.hpp
Normal 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 "OscSinCos.h"
|
||||
|
||||
|
||||
|
||||
namespace ffft
|
||||
{
|
||||
|
||||
|
||||
|
||||
/*\\\ PUBLIC \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/
|
||||
|
||||
|
||||
|
||||
template <int ALGO>
|
||||
void FFTRealUseTrigo <ALGO>::prepare (OscType &osc)
|
||||
{
|
||||
osc.clear_buffers ();
|
||||
}
|
||||
|
||||
template <>
|
||||
inline void FFTRealUseTrigo <0>::prepare (OscType &)
|
||||
{
|
||||
// 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 &, 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
plugins/Cardinal/src/sassy/fftreal/OscSinCos.h
Normal file
107
plugins/Cardinal/src/sassy/fftreal/OscSinCos.h
Normal 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
plugins/Cardinal/src/sassy/fftreal/OscSinCos.hpp
Normal file
123
plugins/Cardinal/src/sassy/fftreal/OscSinCos.hpp
Normal 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
plugins/Cardinal/src/sassy/fftreal/def.h
Normal file
60
plugins/Cardinal/src/sassy/fftreal/def.h
Normal 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 \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/
|
14
plugins/Cardinal/src/sassy/fftreal/license.txt
Normal file
14
plugins/Cardinal/src/sassy/fftreal/license.txt
Normal file
|
@ -0,0 +1,14 @@
|
|||
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
Version 2, December 2004
|
||||
|
||||
Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
|
||||
|
||||
Everyone is permitted to copy and distribute verbatim or modified
|
||||
copies of this license document, and changing it is allowed as long
|
||||
as the name is changed.
|
||||
|
||||
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. You just DO WHAT THE FUCK YOU WANT TO.
|
||||
|
293
plugins/Cardinal/src/sassy/fftreal/readme.txt
Normal file
293
plugins/Cardinal/src/sassy/fftreal/readme.txt
Normal 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
|
||||
|
131
plugins/Cardinal/src/sassy/sassy.hpp
Normal file
131
plugins/Cardinal/src/sassy/sassy.hpp
Normal file
|
@ -0,0 +1,131 @@
|
|||
/*
|
||||
* Sassy scope exported API
|
||||
* Copyright (C) 2022 Filipe Coelho <falktx@falktx.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 3 of
|
||||
* the License, or any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* For a full copy of the GNU General Public License see the LICENSE file.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This file contains a substantial amount of code from Sassy Audio Spreadsheet
|
||||
* Copyright (c) 2022 Jari Komppa.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "fftreal/FFTReal.h"
|
||||
|
||||
// int gFFTAverage = 1;
|
||||
// int gSamplerate;
|
||||
// float mUIScale;
|
||||
// // gScope
|
||||
|
||||
struct ScopeData {
|
||||
int mIndex = 0;
|
||||
int mSampleRate = 0;
|
||||
float mScroll = 0;
|
||||
float mTimeScale = 0.01f;
|
||||
int mTimeScaleSlider = 0;
|
||||
int mSyncMode = 0;
|
||||
int mSyncChannel = 0;
|
||||
int mMode = 0;
|
||||
int mDisplay = 0;
|
||||
int mFFTZoom = 0;
|
||||
int mPot = 0;
|
||||
float fft1[65536 * 2];
|
||||
float fft2[65536 * 2];
|
||||
float ffta[65536 * 2];
|
||||
unsigned int colors[4] = {
|
||||
0xffc0c0c0,
|
||||
0xffa0a0ff,
|
||||
0xffffa0a0,
|
||||
0xff30d0d0
|
||||
};
|
||||
|
||||
struct Channel {
|
||||
bool mEnabled = true;
|
||||
float mScale = 1.0f / 5.0f;
|
||||
int mScaleSlider = 0;
|
||||
float mOffset = 0;
|
||||
float* mData = nullptr;
|
||||
|
||||
~Channel()
|
||||
{
|
||||
delete[] mData;
|
||||
}
|
||||
|
||||
void realloc(const int sampleRate)
|
||||
{
|
||||
mData = new float[sampleRate * 10];
|
||||
memset(mData, 0, sizeof(float) * sampleRate * 10);
|
||||
}
|
||||
} mCh[4];
|
||||
|
||||
struct {
|
||||
int average;
|
||||
ffft::FFTReal<float>* obj16;
|
||||
ffft::FFTReal<float>* obj32;
|
||||
ffft::FFTReal<float>* obj64;
|
||||
ffft::FFTReal<float>* obj128;
|
||||
ffft::FFTReal<float>* obj256;
|
||||
ffft::FFTReal<float>* obj512;
|
||||
ffft::FFTReal<float>* obj1024;
|
||||
ffft::FFTReal<float>* obj2048;
|
||||
ffft::FFTReal<float>* obj4096;
|
||||
ffft::FFTReal<float>* obj8192;
|
||||
ffft::FFTReal<float>* obj16384;
|
||||
ffft::FFTReal<float>* obj32768;
|
||||
ffft::FFTReal<float>* obj65536;
|
||||
} fft;
|
||||
|
||||
void realloc(const int sampleRate)
|
||||
{
|
||||
mIndex = 0;
|
||||
mSampleRate = sampleRate;
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
mCh[i].realloc(sampleRate);
|
||||
}
|
||||
|
||||
inline void probe(float data1, float data2, float data3, float data4)
|
||||
{
|
||||
// since probe has several channels, need to deal with index here
|
||||
if (mMode == 0)
|
||||
{
|
||||
mCh[0].mData[mIndex] = data1;
|
||||
mCh[1].mData[mIndex] = data2;
|
||||
mCh[2].mData[mIndex] = data3;
|
||||
mCh[3].mData[mIndex] = data4;
|
||||
mIndex = (mIndex + 1) % (mSampleRate * 10);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void do_show_scope_window(ScopeData* scope, float uiScale);
|
872
plugins/Cardinal/src/sassy/sassy_scope.cpp
Normal file
872
plugins/Cardinal/src/sassy/sassy_scope.cpp
Normal file
|
@ -0,0 +1,872 @@
|
|||
/*
|
||||
* DISTRHO Cardinal Plugin
|
||||
* Copyright (C) 2021-2022 Filipe Coelho <falktx@falktx.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 3 of
|
||||
* the License, or any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* For a full copy of the GNU General Public License see the LICENSE file.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This file is copied and adapted from Sassy Audio Spreadsheet (sassy_scope.cpp)
|
||||
* Copyright (c) 2022 Jari Komppa.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "sassy.hpp"
|
||||
|
||||
#define POW_2_3_4TH 1.6817928305074290860622509524664297900800685247135690216264521719
|
||||
|
||||
static double catmullrom(double t, double p0, double p1, double p2, double p3)
|
||||
{
|
||||
return 0.5 * (
|
||||
(2 * p1) +
|
||||
(-p0 + p2) * t +
|
||||
(2 * p0 - 5 * p1 + 4 * p2 - p3) * t * t +
|
||||
(-p0 + 3 * p1 - 3 * p2 + p3) * t * t * t
|
||||
);
|
||||
}
|
||||
|
||||
static const char* gNotestr[128] =
|
||||
{
|
||||
"C0-1","C#-1","D-1","D#-1","E-1","F-1","F#-1","G-1","G#-1","A-1","A#-1","B-1",
|
||||
"C0","C#0","D0","D#0","E0","F0","F#0","G0","G#0","A0","A#0","B0",
|
||||
"C1","C#1","D1","D#1","E1","F1","F#1","G1","G#1","A1","A#1","B1",
|
||||
"C2","C#2","D2","D#2","E2","F2","F#2","G2","G#2","A2","A#2","B2",
|
||||
"C3","C#3","D3","D#3","E3","F3","F#3","G3","G#3","A3","A#3","B3",
|
||||
"C4","C#4","D4","D#4","E4","F4","F#4","G4","G#4","A4","A#4","B4",
|
||||
"C5","C#5","D5","D#5","E5","F5","F#5","G5","G#5","A5","A#5","B5",
|
||||
"C6","C#6","D6","D#6","E6","F6","F#6","G6","G#6","A6","A#6","B6",
|
||||
"C7","C#7","D7","D#7","E7","F7","F#7","G7","G#7","A7","A#7","B7",
|
||||
"C8","C#8","D8","D#8","E8","F8","F#8","G8","G#8","A8","A#8","B8",
|
||||
"C9","C#9","D9","D#9","E9","F9","F#9","G9"
|
||||
};
|
||||
|
||||
static const float timescalesteps[5] =
|
||||
{
|
||||
0.0001f,
|
||||
0.001f,
|
||||
0.01f,
|
||||
0.1f,
|
||||
1.0f,
|
||||
};
|
||||
|
||||
static const char* timescaletext[5] =
|
||||
{
|
||||
"0.1ms",
|
||||
"1ms",
|
||||
"10ms",
|
||||
"100ms",
|
||||
"1000ms"
|
||||
};
|
||||
|
||||
static const float scalesteps[9] =
|
||||
{
|
||||
1.0f / 32.0f,
|
||||
1.0f / 16.0f,
|
||||
1.0f / 10.0f,
|
||||
1.0f / 8.0f,
|
||||
1.0f / 5.0f,
|
||||
1.0f / 4.0f,
|
||||
1.0f / 2.0f,
|
||||
1.0f,
|
||||
2.0f,
|
||||
};
|
||||
|
||||
static const char* scaletexts[9] = {
|
||||
"x1/32",
|
||||
"x1/16",
|
||||
"x1/10",
|
||||
"x1/8",
|
||||
"x1/5",
|
||||
"x1/4",
|
||||
"x1/2",
|
||||
"x1",
|
||||
"x2",
|
||||
};
|
||||
|
||||
static constexpr const int grid_size = 340;
|
||||
static constexpr const int grid_half_size = grid_size / 2 + 10;
|
||||
static constexpr const int grid_quarter_size = static_cast<int>(grid_half_size / 2);
|
||||
static constexpr const int grid_1_8_size = grid_quarter_size / 2;
|
||||
static constexpr const int grid_3_8_size = grid_quarter_size + grid_quarter_size / 2;
|
||||
|
||||
static void scope_grid(const float uiScale)
|
||||
{
|
||||
ImVec2 p = ImGui::GetItemRectMin();
|
||||
|
||||
// zero
|
||||
ImGui::GetWindowDrawList()->AddLine(ImVec2(p.x, p.y + (grid_size / 2) * uiScale), ImVec2(p.x + (grid_size) * uiScale, p.y + (grid_size / 2) * uiScale), 0xff000000, 3.0f);
|
||||
// 1.0
|
||||
ImGui::GetWindowDrawList()->AddLine(ImVec2(p.x, p.y + (grid_size / 2 - grid_quarter_size) * uiScale), ImVec2(p.x + (grid_size) * uiScale, p.y + (grid_size / 2 - grid_quarter_size) * uiScale), 0xff000000);
|
||||
ImGui::GetWindowDrawList()->AddLine(ImVec2(p.x, p.y + (grid_size / 2 + grid_quarter_size) * uiScale), ImVec2(p.x + (grid_size) * uiScale, p.y + (grid_size / 2 + grid_quarter_size) * uiScale), 0xff000000);
|
||||
// 0.5
|
||||
ImGui::GetWindowDrawList()->AddLine(ImVec2(p.x, p.y + (grid_size / 2 - grid_1_8_size) * uiScale), ImVec2(p.x + (grid_size) * uiScale, p.y + (grid_size / 2 - grid_1_8_size) * uiScale), 0x3f000000);
|
||||
ImGui::GetWindowDrawList()->AddLine(ImVec2(p.x, p.y + (grid_size / 2 + grid_1_8_size) * uiScale), ImVec2(p.x + (grid_size) * uiScale, p.y + (grid_size / 2 + grid_1_8_size) * uiScale), 0x3f000000);
|
||||
ImGui::GetWindowDrawList()->AddLine(ImVec2(p.x, p.y + (grid_size / 2 - grid_3_8_size) * uiScale), ImVec2(p.x + (grid_size) * uiScale, p.y + (grid_size / 2 - grid_3_8_size) * uiScale), 0x3f000000);
|
||||
ImGui::GetWindowDrawList()->AddLine(ImVec2(p.x, p.y + (grid_size / 2 + grid_3_8_size) * uiScale), ImVec2(p.x + (grid_size) * uiScale, p.y + (grid_size / 2 + grid_3_8_size) * uiScale), 0x3f000000);
|
||||
|
||||
// zero
|
||||
ImGui::GetWindowDrawList()->AddLine(ImVec2(p.x + (grid_size / 2) * uiScale, p.y * uiScale), ImVec2(p.x + (grid_size / 2) * uiScale, p.y + (grid_size) * uiScale), 0xff000000, 3.0f);
|
||||
// 1.0
|
||||
ImGui::GetWindowDrawList()->AddLine(ImVec2(p.x + (grid_size / 2 - grid_quarter_size) * uiScale, p.y * uiScale), ImVec2(p.x + (grid_size / 2 - grid_quarter_size) * uiScale, p.y + (grid_size) * uiScale), 0xff000000);
|
||||
ImGui::GetWindowDrawList()->AddLine(ImVec2(p.x + (grid_size / 2 + grid_quarter_size) * uiScale, p.y * uiScale), ImVec2(p.x + (grid_size / 2 + grid_quarter_size) * uiScale, p.y + (grid_size) * uiScale), 0xff000000);
|
||||
// 0.5
|
||||
ImGui::GetWindowDrawList()->AddLine(ImVec2(p.x + (grid_size / 2 - grid_1_8_size) * uiScale, p.y * uiScale), ImVec2(p.x + (grid_size / 2 - grid_1_8_size) * uiScale, p.y + (grid_size) * uiScale), 0x3f000000);
|
||||
ImGui::GetWindowDrawList()->AddLine(ImVec2(p.x + (grid_size / 2 + grid_1_8_size) * uiScale, p.y * uiScale), ImVec2(p.x + (grid_size / 2 + grid_1_8_size) * uiScale, p.y + (grid_size) * uiScale), 0x3f000000);
|
||||
ImGui::GetWindowDrawList()->AddLine(ImVec2(p.x + (grid_size / 2 - grid_3_8_size) * uiScale, p.y * uiScale), ImVec2(p.x + (grid_size / 2 - grid_3_8_size) * uiScale, p.y + (grid_size) * uiScale), 0x3f000000);
|
||||
ImGui::GetWindowDrawList()->AddLine(ImVec2(p.x + (grid_size / 2 + grid_3_8_size) * uiScale, p.y * uiScale), ImVec2(p.x + (grid_size / 2 + grid_3_8_size) * uiScale, p.y + (grid_size) * uiScale), 0x3f000000);
|
||||
}
|
||||
|
||||
|
||||
static int scope_sync(ScopeData* gScope, int index)
|
||||
{
|
||||
const float gSamplerate = gScope->mSampleRate;
|
||||
int samples = (int)(gSamplerate * gScope->mTimeScale);
|
||||
int cycle = gSamplerate * 10;
|
||||
int ofs = samples;
|
||||
|
||||
if (gScope->mMode == 0)
|
||||
{
|
||||
// calculate sync
|
||||
if (gScope->mSyncMode == 0)
|
||||
{
|
||||
float* graphdata = gScope->mCh[gScope->mSyncChannel].mData;
|
||||
int over = ofs;
|
||||
while (over < (cycle - ofs) && graphdata[(index - over + cycle) % cycle] < 0) over++;
|
||||
int under = over;
|
||||
while (under < (cycle - ofs) && graphdata[(index - under + cycle) % cycle] > 0) under++;
|
||||
ofs = under;
|
||||
}
|
||||
else
|
||||
if (gScope->mSyncMode == 1)
|
||||
{
|
||||
float* graphdata = gScope->mCh[gScope->mSyncChannel].mData;
|
||||
int under = ofs;
|
||||
while (under < (cycle - ofs) && graphdata[(index - under + cycle) % cycle] > 0) under++;
|
||||
int over = under;
|
||||
while (over < (cycle - ofs) && graphdata[(index - over + cycle) % cycle] < 0) over++;
|
||||
ofs = over;
|
||||
}
|
||||
// default: ofs = samples
|
||||
}
|
||||
else
|
||||
{
|
||||
// pause mode, scroll bar is active
|
||||
ofs = -(int)(gScope->mScroll * gSamplerate);
|
||||
if (ofs < samples)
|
||||
ofs = samples;
|
||||
if (ofs > gSamplerate * 10 - samples)
|
||||
ofs = gSamplerate * 10 - samples;
|
||||
}
|
||||
gScope->mScroll = -((float)ofs / gSamplerate);
|
||||
|
||||
return ofs;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static void scope_plot(ScopeData* gScope, const float uiScale, int index)
|
||||
{
|
||||
ImVec2 p = ImGui::GetItemRectMin();
|
||||
const float gSamplerate = gScope->mSampleRate;
|
||||
int cycle = gSamplerate * 10;
|
||||
/*
|
||||
Okay, max scale is 1 second, so..
|
||||
*/
|
||||
int samples = (int)(gSamplerate * gScope->mTimeScale);
|
||||
|
||||
scope_grid(uiScale);
|
||||
|
||||
int ofs = scope_sync(gScope, index);
|
||||
|
||||
if (gScope->mDisplay == 2)
|
||||
{
|
||||
for (int i = 0; i < 16384; i++)
|
||||
{
|
||||
for (int j = 0; j < 4; j++)
|
||||
{
|
||||
if (gScope->mCh[j].mEnabled)
|
||||
{
|
||||
float* graphdata = gScope->mCh[j].mData;
|
||||
float y = graphdata[(index - ofs + i * samples / 16384 + cycle) % cycle];
|
||||
float x = graphdata[(index - ofs + i * samples / 16384 + cycle - 1) % cycle];
|
||||
x = x * gScope->mCh[j].mScale;
|
||||
y = y * gScope->mCh[j].mScale - gScope->mCh[j].mOffset;
|
||||
ImGui::GetWindowDrawList()->AddCircleFilled(
|
||||
ImVec2(p.x + (grid_size / 2 + x * grid_quarter_size) * uiScale, p.y + (grid_size / 2 + y * grid_quarter_size) * uiScale),
|
||||
1,
|
||||
(gScope->colors[j] & 0xffffff) | 0x3f000000);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < 32768; i++)
|
||||
{
|
||||
for (int j = 0; j < 2; j++)
|
||||
{
|
||||
if (gScope->mCh[j*2].mEnabled)
|
||||
{
|
||||
float* graphdata = gScope->mCh[j * 2].mData;
|
||||
float x = graphdata[(index - ofs + i * samples / 32768 + cycle) % cycle];
|
||||
graphdata = gScope->mCh[j * 2 + 1].mData;
|
||||
float y = graphdata[(index - ofs + i * samples / 32768 + cycle) % cycle];
|
||||
x = x * gScope->mCh[j * 2].mScale - gScope->mCh[j * 2].mOffset;
|
||||
y = y * gScope->mCh[j * 2 + 1].mScale - gScope->mCh[j * 2 + 1].mOffset;
|
||||
ImGui::GetWindowDrawList()->AddCircleFilled(
|
||||
ImVec2(p.x + (grid_size / 2 + x * grid_quarter_size) * uiScale, p.y + (grid_size / 2 + y * grid_quarter_size) * uiScale),
|
||||
1,
|
||||
(gScope->colors[j*2] & 0xffffff) | 0x3f000000);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
static void scope_time(ScopeData* gScope, const float uiScale, int index)
|
||||
{
|
||||
ImVec2 p = ImGui::GetItemRectMin();
|
||||
const float gSamplerate = gScope->mSampleRate;
|
||||
int cycle = gSamplerate * 10;
|
||||
ImDrawList* dl = ImGui::GetWindowDrawList();
|
||||
/*
|
||||
Okay, max scale is 1 second, so..
|
||||
*/
|
||||
int samples = (int)(gSamplerate * gScope->mTimeScale);
|
||||
|
||||
scope_grid(uiScale);
|
||||
|
||||
int ofs = scope_sync(gScope, index);
|
||||
|
||||
if (samples > grid_size)
|
||||
{
|
||||
for (int j = 0; j < 4; j++)
|
||||
{
|
||||
if (gScope->mCh[j].mEnabled)
|
||||
{
|
||||
float* graphdata = gScope->mCh[j].mData;
|
||||
ImVec2 vert[grid_size];
|
||||
for (int i = 0; i < grid_size; i++)
|
||||
{
|
||||
float v0 = -graphdata[(index - ofs + i * samples / grid_size + cycle) % cycle];
|
||||
float v1 = -graphdata[(index - ofs + (i + 1) * samples / grid_size + cycle) % cycle];
|
||||
v0 = v0 * gScope->mCh[j].mScale - gScope->mCh[j].mOffset;
|
||||
v1 = v1 * gScope->mCh[j].mScale - gScope->mCh[j].mOffset;
|
||||
vert[i].x = p.x + i * uiScale;
|
||||
vert[i].y = p.y + (grid_size / 2 + v0 * grid_quarter_size) * uiScale;
|
||||
}
|
||||
float v0 = p.y + (grid_size / 2 + (-gScope->mCh[j].mOffset) * grid_quarter_size) * uiScale;
|
||||
dl->Flags = 0;
|
||||
for (int i = 0; i < grid_size-1; i++)
|
||||
{
|
||||
ImVec2 quad[4];
|
||||
quad[0] = ImVec2(vert[i].x, v0);
|
||||
quad[1] = ImVec2(vert[i].x, vert[i].y);
|
||||
quad[2] = ImVec2(vert[i + 1].x, vert[i + 1].y);
|
||||
quad[3] = ImVec2(vert[i + 1].x, v0);
|
||||
dl->AddConvexPolyFilled(quad, 4, (gScope->colors[j] & 0xffffff) | 0x3f000000 );
|
||||
|
||||
}
|
||||
|
||||
if (gScope->mTimeScale < 0.1)
|
||||
{
|
||||
dl->Flags = ImDrawListFlags_AntiAliasedLines;
|
||||
dl->AddPolyline(vert, grid_size, gScope->colors[j], false, 2 * uiScale);
|
||||
}
|
||||
else
|
||||
{
|
||||
dl->Flags = ImDrawListFlags_AntiAliasedLines;
|
||||
dl->AddPolyline(vert, grid_size, gScope->colors[j], false, 1);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// less than 1 sample per pixel
|
||||
for (int j = 0; j < 4; j++)
|
||||
{
|
||||
if (gScope->mCh[j].mEnabled)
|
||||
{
|
||||
float* graphdata = gScope->mCh[j].mData;
|
||||
for (int i = 0; i < samples; i++)
|
||||
{
|
||||
float v0 = -graphdata[(index - ofs + i + cycle) % cycle];
|
||||
float v1 = 0;
|
||||
v0 = v0 * gScope->mCh[j].mScale - gScope->mCh[j].mOffset;
|
||||
v1 = v1 * gScope->mCh[j].mScale - gScope->mCh[j].mOffset;
|
||||
float x0 = p.x + (i * grid_size / samples) * uiScale;
|
||||
ImGui::GetWindowDrawList()->AddCircleFilled(
|
||||
ImVec2(x0, p.y + (grid_size / 2 + v0 * grid_quarter_size) * uiScale),
|
||||
4 * uiScale,
|
||||
gScope->colors[j]);
|
||||
ImGui::GetWindowDrawList()->AddLine(
|
||||
ImVec2(x0, p.y + (grid_size / 2 + v0 * grid_quarter_size) * uiScale),
|
||||
ImVec2(x0, p.y + (grid_size / 2 + v1 * grid_quarter_size) * uiScale),
|
||||
gScope->colors[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::GetWindowDrawList()->AddText(p, 0xffc0c0c0, timescaletext[gScope->mTimeScaleSlider + 2]);
|
||||
ImGui::GetWindowDrawList()->AddText(ImVec2(p.x, p.y + (grid_size / 2 - grid_quarter_size - 7) * uiScale), 0xffc0c0c0, "+1");
|
||||
ImGui::GetWindowDrawList()->AddText(ImVec2(p.x, p.y + (grid_size / 2 + grid_quarter_size - 7) * uiScale), 0xffc0c0c0, "-1");
|
||||
|
||||
ImVec2 mp = ImGui::GetMousePos();
|
||||
mp.x -= p.x;
|
||||
mp.y -= p.y;
|
||||
if (mp.x > 0 && mp.x < grid_size * uiScale &&
|
||||
mp.y > 0 && mp.y < grid_size * uiScale)
|
||||
{
|
||||
ImGui::GetWindowDrawList()->AddLine(
|
||||
ImVec2(p.x + mp.x, p.y),
|
||||
ImVec2(p.x + mp.x, p.y + grid_size * uiScale),
|
||||
0xff00ff00, 1 * uiScale);
|
||||
if (gScope->mCh[0].mEnabled || gScope->mCh[1].mEnabled || gScope->mCh[2].mEnabled || gScope->mCh[3].mEnabled)
|
||||
{
|
||||
ImGui::BeginTooltip();
|
||||
if (gScope->mCh[0].mEnabled) ImGui::Text("Ch 0: %3.3f", gScope->mCh[0].mData[(index - ofs + ((int)mp.x / (int)uiScale) * samples / grid_size + cycle) % cycle]);
|
||||
if (gScope->mCh[1].mEnabled) ImGui::Text("Ch 1: %3.3f", gScope->mCh[1].mData[(index - ofs + ((int)mp.x / (int)uiScale) * samples / grid_size + cycle) % cycle]);
|
||||
if (gScope->mCh[2].mEnabled) ImGui::Text("Ch 2: %3.3f", gScope->mCh[2].mData[(index - ofs + ((int)mp.x / (int)uiScale) * samples / grid_size + cycle) % cycle]);
|
||||
if (gScope->mCh[3].mEnabled) ImGui::Text("Ch 3: %3.3f", gScope->mCh[3].mData[(index - ofs + ((int)mp.x / (int)uiScale) * samples / grid_size + cycle) % cycle]);
|
||||
ImGui::EndTooltip();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void vertline(const float uiScale, const float x, const float w)
|
||||
{
|
||||
ImVec2 p = ImGui::GetItemRectMin();
|
||||
ImGui::GetWindowDrawList()->AddLine(ImVec2(p.x + x * uiScale, p.y * uiScale), ImVec2(p.x + x * uiScale, p.y + (grid_size) * uiScale), 0xff000000, w);
|
||||
}
|
||||
|
||||
static void scope_freq(ScopeData* gScope, const float uiScale, int index)
|
||||
{
|
||||
ImVec2 p = ImGui::GetItemRectMin();
|
||||
ImDrawList* dl = ImGui::GetWindowDrawList();
|
||||
const float gSamplerate = gScope->mSampleRate;
|
||||
int cycle = gSamplerate * 10;
|
||||
/*
|
||||
Okay, max scale is 1 second, so..
|
||||
*/
|
||||
int samples = (int)(gSamplerate * gScope->mTimeScale);
|
||||
|
||||
// what's the biggest PoT < samples?
|
||||
// 192000 takes 18 bits to encode.
|
||||
// Fill 32 bits:
|
||||
int pot = samples | (samples >> 16);
|
||||
pot = pot | (pot >> 8);
|
||||
pot = pot | (pot >> 4);
|
||||
pot = pot | (pot >> 2);
|
||||
pot = pot | (pot >> 1);
|
||||
// Shift down and add one to round it up
|
||||
pot = (pot >> 1) + 1;
|
||||
|
||||
if (pot < 16) pot = 16;
|
||||
if (pot > 65536) pot = 65536;
|
||||
|
||||
gScope->mPot = pot;
|
||||
|
||||
ffft::FFTReal<float>* fft = NULL;
|
||||
switch (pot)
|
||||
{
|
||||
case 16: fft = gScope->fft.obj16; break;
|
||||
case 32: fft = gScope->fft.obj32; break;
|
||||
case 64: fft = gScope->fft.obj64; break;
|
||||
case 128: fft = gScope->fft.obj128; break;
|
||||
case 256: fft = gScope->fft.obj256; break;
|
||||
case 512: fft = gScope->fft.obj512; break;
|
||||
case 1024: fft = gScope->fft.obj1024; break;
|
||||
case 2048: fft = gScope->fft.obj2048; break;
|
||||
case 4096: fft = gScope->fft.obj4096; break;
|
||||
case 8192: fft = gScope->fft.obj8192; break;
|
||||
case 16384: fft = gScope->fft.obj16384; break;
|
||||
case 32768: fft = gScope->fft.obj32768; break;
|
||||
case 65536: fft = gScope->fft.obj65536; break;
|
||||
}
|
||||
if (!fft) return;
|
||||
|
||||
int average = gScope->fft.average;
|
||||
int ofs = scope_sync(gScope, index);
|
||||
int size = grid_size - 1;
|
||||
float sizef = size;
|
||||
float freqbin = gSamplerate / (float)(pot / 2);
|
||||
float freqbins[size];
|
||||
float zoom = 1.0f / (1 << gScope->mFFTZoom);
|
||||
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
vertline(uiScale, sqrt(100 / freqbin * i / (pot / 4)) / zoom * sizef, 1);
|
||||
vertline(uiScale, sqrt(1000 / freqbin * i / (pot / 4)) / zoom * sizef, 1);
|
||||
vertline(uiScale, sqrt(10000 / freqbin * i / (pot / 4)) / zoom * sizef, 1);
|
||||
}
|
||||
|
||||
for (int j = 0; j < 4; j++)
|
||||
{
|
||||
if (gScope->mCh[j].mEnabled)
|
||||
{
|
||||
|
||||
|
||||
memset(gScope->ffta, 0, sizeof(float) * 65536 * 2);
|
||||
for (int k = 0; k < average; k++)
|
||||
{
|
||||
float* graphdata = gScope->mCh[j].mData;
|
||||
|
||||
for (int i = 0; i < pot; i++)
|
||||
{
|
||||
gScope->fft1[i * 2] = graphdata[(index - ofs + i + cycle - k) % cycle];
|
||||
gScope->fft1[i * 2 + 1] = 0;
|
||||
}
|
||||
|
||||
fft->do_fft(gScope->fft2, gScope->fft1);
|
||||
|
||||
for (int i = 0; i < pot / 4; i++)
|
||||
gScope->ffta[i] += (1.0f / average) * sqrt(gScope->fft2[i * 2 + 0] * gScope->fft2[i * 2 + 0] + gScope->fft2[i * 2 + 1] * gScope->fft2[i * 2 + 1]);
|
||||
}
|
||||
|
||||
ImVec2 vert[size];
|
||||
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
float ppos = powf(zoom * i / sizef, 2.0f) * pot / 4;
|
||||
freqbins[i] = ppos * freqbin;
|
||||
|
||||
float f = ppos - (int)ppos;
|
||||
float a = i ? gScope->ffta[(int)ppos - 1] : 0;
|
||||
float b = gScope->ffta[(int)ppos];
|
||||
float c = i < size ? gScope->ffta[(int)ppos + 1] : 0;
|
||||
float d = i < (size-1) ? gScope->ffta[(int)ppos + 2] : 0;
|
||||
|
||||
float v0 = (float)catmullrom(f, a, b, c, d);
|
||||
|
||||
v0 = v0 * gScope->mCh[j].mScale + gScope->mCh[j].mOffset * 50;
|
||||
vert[i] = ImVec2(p.x + i * uiScale,
|
||||
p.y + (sizef - v0 * 4) * uiScale);
|
||||
}
|
||||
float v0 = p.y + (size - gScope->mCh[j].mOffset * 50 * 4) * uiScale;
|
||||
dl->Flags = 0;
|
||||
for (int i = 0; i < size-1; i++)
|
||||
{
|
||||
ImVec2 quad[4];
|
||||
quad[0] = ImVec2(vert[i].x, v0);
|
||||
quad[1] = ImVec2(vert[i].x, vert[i].y);
|
||||
quad[2] = ImVec2(vert[i + 1].x, vert[i + 1].y);
|
||||
quad[3] = ImVec2(vert[i + 1].x, v0);
|
||||
dl->AddConvexPolyFilled(quad, 4, (gScope->colors[j] & 0xffffff) | 0x3f000000);
|
||||
|
||||
}
|
||||
|
||||
dl->Flags = ImDrawListFlags_AntiAliasedLines;
|
||||
dl->AddPolyline(vert, size, gScope->colors[j], false, 1);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (!ImGui::IsPopupOpen("Freq Context",ImGuiPopupFlags_AnyPopupId))
|
||||
if (gScope->mCh[0].mEnabled || gScope->mCh[1].mEnabled || gScope->mCh[2].mEnabled || gScope->mCh[3].mEnabled)
|
||||
{
|
||||
ImVec2 mp = ImGui::GetMousePos();
|
||||
mp.x -= p.x;
|
||||
mp.y -= p.y;
|
||||
if (mp.x > 0 && mp.x < grid_size * uiScale &&
|
||||
mp.y > 0 && mp.y < grid_size * uiScale)
|
||||
{
|
||||
ImGui::GetWindowDrawList()->AddLine(
|
||||
ImVec2(p.x + mp.x, p.y),
|
||||
ImVec2(p.x + mp.x, p.y + grid_size * uiScale),
|
||||
0xff00ff00, 1 * uiScale);
|
||||
ImGui::BeginTooltip();
|
||||
int note = (int)(12 * log(32 * POW_2_3_4TH * (freqbins[(int)mp.x] / 440)) / log(2));
|
||||
if (note < 0 || note > 127) note = -1;
|
||||
ImGui::Text("%3.3fHz%s%s", freqbins[(int)mp.x], note==-1?"":"\n", note==-1?"":gNotestr[note]);
|
||||
ImGui::EndTooltip();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
static int groups(ScopeData* gScope, double h)
|
||||
{
|
||||
int count = 0;
|
||||
for (int i = 1; i < gScope->mPot / 4; i++)
|
||||
{
|
||||
if (gScope->fft1[i - 1] < h && gScope->fft1[i] > h)
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
static void detect_fundamentals(ScopeData* gScope)
|
||||
{
|
||||
// gScope->fft1[1..pot/4] has our mags
|
||||
double maxmag = 0;
|
||||
for (int i = 0; i < gScope->mPot / 4; i++)
|
||||
if (maxmag < gScope->fft1[i])
|
||||
maxmag = gScope->fft1[i];
|
||||
|
||||
double minmag = 0;
|
||||
int count = 0;
|
||||
int iters = 0;
|
||||
double h = (minmag + maxmag) / 2;
|
||||
double step = h / 2;
|
||||
while (iters < 100 && count != 16)
|
||||
{
|
||||
count = groups(gScope, h);
|
||||
if (count < 16)
|
||||
{
|
||||
h -= step;
|
||||
}
|
||||
else
|
||||
{
|
||||
h += step;
|
||||
}
|
||||
step /= 2;
|
||||
iters++;
|
||||
}
|
||||
char temp[1024];
|
||||
int ofs = 0;
|
||||
temp[0] = 0;
|
||||
const float gSamplerate = gScope->mSampleRate;
|
||||
float freqbin = gSamplerate / (float)(gScope->mPot / 2);
|
||||
|
||||
int startbin = 0;
|
||||
for (int i = 2; i < gScope->mPot / 4; i++)
|
||||
{
|
||||
if (gScope->fft1[i - 1] < h && gScope->fft1[i] > h)
|
||||
{
|
||||
startbin = i;
|
||||
}
|
||||
if (gScope->fft1[i - 1] > h && gScope->fft1[i] < h)
|
||||
{
|
||||
double sum = 0;
|
||||
double magsum = 0;
|
||||
for (int j = startbin; j < i; j++)
|
||||
{
|
||||
sum += gScope->fft1[j];
|
||||
magsum += gScope->fft1[j] * j * freqbin;
|
||||
}
|
||||
if (sum != 0)
|
||||
{
|
||||
magsum /= sum;
|
||||
sum /= i - startbin;
|
||||
sum /= maxmag / 2; // normalize
|
||||
ofs += sprintf(temp + ofs, "%3.3f\t%3.3f\n", magsum, sum);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
}
|
||||
ImGui::SetClipboardText(temp);
|
||||
}
|
||||
#endif
|
||||
|
||||
void do_show_scope_window(ScopeData* gScope, const float uiScale)
|
||||
{
|
||||
// Data is updated live, so let's take local copies of critical stuff.
|
||||
int index = gScope->mIndex;
|
||||
|
||||
ImGui::Begin("Scope", nullptr, ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize);
|
||||
|
||||
ImGui::BeginChild("Channel options", ImVec2((4 * 25)*uiScale, (2 * 152 + 32) * uiScale));
|
||||
ImGui::Checkbox("###ea", &gScope->mCh[0].mEnabled); ImGui::SameLine();
|
||||
ImGui::Checkbox("###eb", &gScope->mCh[1].mEnabled); ImGui::SameLine();
|
||||
ImGui::Checkbox("###ec", &gScope->mCh[2].mEnabled); ImGui::SameLine();
|
||||
ImGui::Checkbox("###ed", &gScope->mCh[3].mEnabled);
|
||||
|
||||
ImGui::PushStyleColor(ImGuiCol_SliderGrab, gScope->colors[0]); ImGui::PushStyleColor(ImGuiCol_SliderGrabActive, gScope->colors[0]);
|
||||
if (ImGui::VSliderInt("###0a", ImVec2(19 * uiScale, 150 * uiScale), &gScope->mCh[0].mScaleSlider, -4, 4, ""))
|
||||
{
|
||||
if (ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left))
|
||||
{
|
||||
gScope->mCh[0].mScaleSlider = 0;
|
||||
gScope->mCh[0].mScale = scalesteps[4];
|
||||
}
|
||||
else
|
||||
{
|
||||
gScope->mCh[0].mScale = scalesteps[gScope->mCh[0].mScaleSlider + 4];
|
||||
}
|
||||
}
|
||||
if (ImGui::IsItemHovered())
|
||||
{
|
||||
ImGui::BeginTooltip();
|
||||
ImGui::Text("%s", scaletexts[gScope->mCh[0].mScaleSlider + 4]);
|
||||
ImGui::EndTooltip();
|
||||
}
|
||||
ImGui::PopStyleColor(2); ImGui::SameLine();
|
||||
ImGui::PushStyleColor(ImGuiCol_SliderGrab, gScope->colors[1]); ImGui::PushStyleColor(ImGuiCol_SliderGrabActive, gScope->colors[1]);
|
||||
if (ImGui::VSliderInt("###1a", ImVec2(19 * uiScale, 150 * uiScale), &gScope->mCh[1].mScaleSlider, -4, 4, ""))
|
||||
{
|
||||
gScope->mCh[1].mScale = scalesteps[gScope->mCh[1].mScaleSlider + 4];
|
||||
}
|
||||
if (ImGui::IsItemHovered())
|
||||
{
|
||||
ImGui::BeginTooltip();
|
||||
ImGui::Text("%s", scaletexts[gScope->mCh[1].mScaleSlider + 4]);
|
||||
ImGui::EndTooltip();
|
||||
}
|
||||
ImGui::PopStyleColor(2); ImGui::SameLine();
|
||||
ImGui::PushStyleColor(ImGuiCol_SliderGrab, gScope->colors[2]); ImGui::PushStyleColor(ImGuiCol_SliderGrabActive, gScope->colors[2]);
|
||||
if (ImGui::VSliderInt("###2a", ImVec2(19 * uiScale, 150 * uiScale), &gScope->mCh[2].mScaleSlider, -4, 4, ""))
|
||||
{
|
||||
gScope->mCh[2].mScale = scalesteps[gScope->mCh[2].mScaleSlider + 4];
|
||||
}
|
||||
if (ImGui::IsItemHovered())
|
||||
{
|
||||
ImGui::BeginTooltip();
|
||||
ImGui::Text("%s", scaletexts[gScope->mCh[2].mScaleSlider + 4]);
|
||||
ImGui::EndTooltip();
|
||||
}
|
||||
ImGui::PopStyleColor(2); ImGui::SameLine();
|
||||
ImGui::PushStyleColor(ImGuiCol_SliderGrab, gScope->colors[3]); ImGui::PushStyleColor(ImGuiCol_SliderGrabActive, gScope->colors[3]);
|
||||
if (ImGui::VSliderInt("###3a", ImVec2(19 * uiScale, 150 * uiScale), &gScope->mCh[3].mScaleSlider, -4, 4, ""))
|
||||
{
|
||||
gScope->mCh[3].mScale = scalesteps[gScope->mCh[3].mScaleSlider + 4];
|
||||
}
|
||||
if (ImGui::IsItemHovered())
|
||||
{
|
||||
ImGui::BeginTooltip();
|
||||
ImGui::Text("%s", scaletexts[gScope->mCh[3].mScaleSlider + 4]);
|
||||
ImGui::EndTooltip();
|
||||
}
|
||||
ImGui::PopStyleColor(2);
|
||||
|
||||
ImGui::PushStyleColor(ImGuiCol_SliderGrab, gScope->colors[0]); ImGui::PushStyleColor(ImGuiCol_SliderGrabActive, gScope->colors[0]); ImGui::VSliderFloat("###0b", ImVec2(19 * uiScale, 150 * uiScale), &gScope->mCh[0].mOffset, -2, 2, ""); ImGui::PopStyleColor(2); ImGui::SameLine();
|
||||
if (ImGui::IsItemHovered())
|
||||
{
|
||||
ImGui::BeginTooltip();
|
||||
ImGui::Text("%3.3f", gScope->mCh[0].mOffset);
|
||||
ImGui::EndTooltip();
|
||||
}
|
||||
ImGui::PushStyleColor(ImGuiCol_SliderGrab, gScope->colors[1]); ImGui::PushStyleColor(ImGuiCol_SliderGrabActive, gScope->colors[1]); ImGui::VSliderFloat("###1b", ImVec2(19 * uiScale, 150 * uiScale), &gScope->mCh[1].mOffset, -2, 2, ""); ImGui::PopStyleColor(2); ImGui::SameLine();
|
||||
if (ImGui::IsItemHovered())
|
||||
{
|
||||
ImGui::BeginTooltip();
|
||||
ImGui::Text("%3.3f", gScope->mCh[1].mOffset);
|
||||
ImGui::EndTooltip();
|
||||
}
|
||||
ImGui::PushStyleColor(ImGuiCol_SliderGrab, gScope->colors[2]); ImGui::PushStyleColor(ImGuiCol_SliderGrabActive, gScope->colors[2]); ImGui::VSliderFloat("###2b", ImVec2(19 * uiScale, 150 * uiScale), &gScope->mCh[2].mOffset, -2, 2, ""); ImGui::PopStyleColor(2); ImGui::SameLine();
|
||||
if (ImGui::IsItemHovered())
|
||||
{
|
||||
ImGui::BeginTooltip();
|
||||
ImGui::Text("%3.3f", gScope->mCh[2].mOffset);
|
||||
ImGui::EndTooltip();
|
||||
}
|
||||
ImGui::PushStyleColor(ImGuiCol_SliderGrab, gScope->colors[3]); ImGui::PushStyleColor(ImGuiCol_SliderGrabActive, gScope->colors[3]); ImGui::VSliderFloat("###3b", ImVec2(19 * uiScale, 150 * uiScale), &gScope->mCh[3].mOffset, -2, 2, ""); ImGui::PopStyleColor(2);
|
||||
if (ImGui::IsItemHovered())
|
||||
{
|
||||
ImGui::BeginTooltip();
|
||||
ImGui::Text("%3.3f", gScope->mCh[3].mOffset);
|
||||
ImGui::EndTooltip();
|
||||
}
|
||||
ImGui::EndChild();
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
ImGui::PushStyleColor(ImGuiCol_ChildBg, ImGui::GetStyle().Colors[ImGuiCol_FrameBg]);
|
||||
ImGui::BeginChild("Scope and scroll", ImVec2(grid_size * uiScale, (grid_size + 24)* uiScale));
|
||||
ImGui::BeginChild("Scope proper", ImVec2(grid_size * uiScale, grid_size * uiScale));
|
||||
|
||||
if (gScope->mDisplay == 0)
|
||||
scope_time(gScope, uiScale, index);
|
||||
if (gScope->mDisplay == 1)
|
||||
scope_freq(gScope, uiScale, index);
|
||||
/*
|
||||
if (gScope->mDisplay == 2 || gScope->mDisplay == 3)
|
||||
scope_plot(gScope, uiScale, index);
|
||||
*/
|
||||
|
||||
ImGui::EndChild();
|
||||
ImGui::PopStyleColor(1);
|
||||
/*
|
||||
if (gScope->mDisplay == 1)
|
||||
{
|
||||
if (ImGui::BeginPopupContextItem("Freq Context"))
|
||||
{
|
||||
if (ImGui::BeginMenu("Experimental.."))
|
||||
{
|
||||
if (ImGui::MenuItem("Detect and copy fundamental frequencies"))
|
||||
{
|
||||
detect_fundamentals(gScope);
|
||||
}
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
if (ImGui::BeginMenu("Averaging.."))
|
||||
{
|
||||
if (ImGui::MenuItem("1x"))
|
||||
gScope->fft.average = 1;
|
||||
if (ImGui::MenuItem("4x"))
|
||||
gScope->fft.average = 4;
|
||||
if (ImGui::MenuItem("16x"))
|
||||
gScope->fft.average = 16;
|
||||
if (ImGui::MenuItem("64x"))
|
||||
gScope->fft.average = 64;
|
||||
if (ImGui::MenuItem("256x"))
|
||||
gScope->fft.average = 256;
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
}
|
||||
//context_menu(1, 1, 1);
|
||||
*/
|
||||
|
||||
if (gScope->mMode)
|
||||
{
|
||||
ImGui::SetNextItemWidth(grid_size * uiScale);
|
||||
ImGui::SliderFloat("###scroll", &gScope->mScroll, -10.0f, 0.0f, "%.3f s");
|
||||
}
|
||||
else
|
||||
{
|
||||
ImGui::PushStyleColor(ImGuiCol_FrameBg, 0xff3f3f3f);
|
||||
ImGui::PushStyleColor(ImGuiCol_FrameBgActive, 0xff3f3f3f);
|
||||
ImGui::PushStyleColor(ImGuiCol_FrameBgHovered, 0xff3f3f3f);
|
||||
ImGui::PushStyleColor(ImGuiCol_SliderGrab, 0xff7f7f7f);
|
||||
ImGui::PushStyleColor(ImGuiCol_SliderGrabActive, 0xff7f7f7f);
|
||||
ImGui::SetNextItemWidth(grid_size * uiScale);
|
||||
float x = gScope->mScroll;
|
||||
ImGui::SliderFloat("###scroll", &x, -10.0f, 0.0f, "%.3f s");
|
||||
ImGui::PopStyleColor(5);
|
||||
}
|
||||
ImGui::EndChild();
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
ImGui::BeginChild("Scope options", ImVec2((4 * 21) * uiScale, 364 * uiScale));
|
||||
if (ImGui::VSliderInt("###0a", ImVec2(19 * uiScale, 155 * uiScale), &gScope->mTimeScaleSlider, -2, 2, ""))
|
||||
{
|
||||
gScope->mTimeScale = timescalesteps[gScope->mTimeScaleSlider + 2];
|
||||
}
|
||||
if (ImGui::IsItemHovered())
|
||||
{
|
||||
ImGui::BeginTooltip();
|
||||
ImGui::Text("%s", timescaletext[gScope->mTimeScaleSlider + 2]);
|
||||
ImGui::EndTooltip();
|
||||
}
|
||||
ImGui::SameLine();
|
||||
ImGui::BeginChild("moderadio", ImVec2(100 * uiScale, 155 * uiScale));
|
||||
if (ImGui::RadioButton("Time", gScope->mDisplay == 0)) gScope->mDisplay = 0;
|
||||
if (ImGui::RadioButton("Freq", gScope->mDisplay == 1)) gScope->mDisplay = 1;
|
||||
/*
|
||||
if (ImGui::RadioButton("X,X'", gScope->mDisplay == 2)) gScope->mDisplay = 2;
|
||||
if (ImGui::RadioButton("X,Y", gScope->mDisplay == 3)) gScope->mDisplay = 3;
|
||||
*/
|
||||
ImGui::Separator();
|
||||
ImGui::Text("FFT");
|
||||
if (ImGui::RadioButton("1x", gScope->mFFTZoom == 0)) gScope->mFFTZoom = 0;
|
||||
if (ImGui::RadioButton("2x", gScope->mFFTZoom == 1)) gScope->mFFTZoom = 1;
|
||||
if (ImGui::RadioButton("4x", gScope->mFFTZoom == 2)) gScope->mFFTZoom = 2;
|
||||
if (ImGui::RadioButton("8x", gScope->mFFTZoom == 3)) gScope->mFFTZoom = 3;
|
||||
ImGui::EndChild();
|
||||
char temp[64];
|
||||
sprintf(temp, "Sync ch %d###sc", gScope->mSyncChannel + 1);
|
||||
if (ImGui::Button(temp, ImVec2(80 * uiScale, 20 * uiScale)))
|
||||
gScope->mSyncChannel = (gScope->mSyncChannel + 1) % 4;
|
||||
const char* syncmodes[3] = { "^", "v", "off" };
|
||||
sprintf(temp, "Sync %s###sm", syncmodes[gScope->mSyncMode]);
|
||||
if (ImGui::Button(temp, ImVec2(80 * uiScale, 20 * uiScale)))
|
||||
gScope->mSyncMode = (gScope->mSyncMode + 1) % 3;
|
||||
|
||||
if (gScope->mMode == 0)
|
||||
{
|
||||
if (ImGui::Button("Pause", ImVec2(80 * uiScale, 20 * uiScale)))
|
||||
gScope->mMode = 1;
|
||||
ImGui::Text("Nudge (ms)");
|
||||
ImGui::PushStyleColor(ImGuiCol_Button, 0xff3f3f3f);
|
||||
ImGui::PushStyleColor(ImGuiCol_ButtonActive, 0xff3f3f3f);
|
||||
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, 0xff3f3f3f);
|
||||
ImGui::Button("-0.1", ImVec2(38 * uiScale, 20 * uiScale));
|
||||
ImGui::SameLine();
|
||||
ImGui::Button("+0.1", ImVec2(38 * uiScale, 20 * uiScale));
|
||||
ImGui::Button("-1", ImVec2(38 * uiScale, 20 * uiScale));
|
||||
ImGui::SameLine();
|
||||
ImGui::Button("+1", ImVec2(38 * uiScale, 20 * uiScale));
|
||||
ImGui::Button("-10", ImVec2(38 * uiScale, 20 * uiScale));
|
||||
ImGui::SameLine();
|
||||
ImGui::Button("+10", ImVec2(38 * uiScale, 20 * uiScale));
|
||||
ImGui::Button("-100", ImVec2(38 * uiScale, 20 * uiScale));
|
||||
ImGui::SameLine();
|
||||
ImGui::Button("+100", ImVec2(38 * uiScale, 20 * uiScale));
|
||||
ImGui::PopStyleColor(3);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ImGui::Button("Capture", ImVec2(80 * uiScale, 20 * uiScale)))
|
||||
gScope->mMode = 0;
|
||||
ImGui::Text("Nudge (ms)");
|
||||
if (ImGui::Button("-0.1", ImVec2(38 * uiScale, 20 * uiScale)))
|
||||
{
|
||||
gScope->mScroll -= 0.0001f;
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("+0.1", ImVec2(38 * uiScale, 20 * uiScale)))
|
||||
{
|
||||
gScope->mScroll += 0.0001f;
|
||||
}
|
||||
if (ImGui::Button("-1", ImVec2(38 * uiScale, 20 * uiScale)))
|
||||
{
|
||||
gScope->mScroll -= 0.001f;
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("+1", ImVec2(38 * uiScale, 20 * uiScale)))
|
||||
{
|
||||
gScope->mScroll += 0.001f;
|
||||
}
|
||||
if (ImGui::Button("-10", ImVec2(38 * uiScale, 20 * uiScale)))
|
||||
{
|
||||
gScope->mScroll -= 0.01f;
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("+10", ImVec2(38 * uiScale, 20 * uiScale)))
|
||||
{
|
||||
gScope->mScroll += 0.01f;
|
||||
}
|
||||
if (ImGui::Button("-100", ImVec2(38 * uiScale, 20 * uiScale)))
|
||||
{
|
||||
gScope->mScroll -= 0.1f;
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("+100", ImVec2(38 * uiScale, 20 * uiScale)))
|
||||
{
|
||||
gScope->mScroll += 0.1f;
|
||||
}
|
||||
}
|
||||
ImGui::EndChild();
|
||||
|
||||
ImGui::End();
|
||||
|
||||
}
|
|
@ -218,6 +218,8 @@ endif
|
|||
ifneq ($(HEADLESS),true)
|
||||
PLUGIN_FILES += Cardinal/src/ImGuiWidget.cpp
|
||||
PLUGIN_FILES += Cardinal/src/ImGuiTextEditor.cpp
|
||||
PLUGIN_FILES += Cardinal/src/SassyScope.cpp
|
||||
# PLUGIN_FILES += Cardinal/src/sassy/sassy_scope.cpp
|
||||
PLUGIN_FILES += $(wildcard Cardinal/src/DearImGui/*.cpp)
|
||||
PLUGIN_FILES += $(wildcard Cardinal/src/DearImGuiColorTextEditor/*.cpp)
|
||||
endif
|
||||
|
|
|
@ -878,6 +878,11 @@ static void initStatic__Cardinal()
|
|||
spl.removeModule("Carla");
|
||||
spl.removeModule("Ildaeil");
|
||||
#endif
|
||||
#ifndef HEADLESS
|
||||
p->addModel(modelSassyScope);
|
||||
#else
|
||||
spl.removeModule("SassyScope");
|
||||
#endif
|
||||
#if defined(HAVE_X11) && !defined(HEADLESS) && !defined(STATIC_BUILD)
|
||||
p->addModel(modelMPV);
|
||||
#else
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue