Browse Source

Import roth-air plugin

Signed-off-by: falkTX <falktx@falktx.com>
roth-air
falkTX 2 years ago
parent
commit
3d2c5078dd
Signed by: falkTX <falktx@falktx.com> GPG Key ID: CDBAA37ABC74FBA0
71 changed files with 17871 additions and 0 deletions
  1. +1
    -0
      meson_options.txt
  2. +1
    -0
      ports-juce6/meson.build
  3. +4945
    -0
      ports-juce6/roth-air/BinaryData.cpp
  4. +63
    -0
      ports-juce6/roth-air/BinaryData.h
  5. +295
    -0
      ports-juce6/roth-air/Compressor.cpp
  6. +103
    -0
      ports-juce6/roth-air/Compressor.h
  7. +485
    -0
      ports-juce6/roth-air/DspFilters/Bessel.h
  8. +232
    -0
      ports-juce6/roth-air/DspFilters/Biquad.h
  9. +436
    -0
      ports-juce6/roth-air/DspFilters/Butterworth.h
  10. +181
    -0
      ports-juce6/roth-air/DspFilters/Cascade.h
  11. +465
    -0
      ports-juce6/roth-air/DspFilters/ChebyshevI.h
  12. +466
    -0
      ports-juce6/roth-air/DspFilters/ChebyshevII.h
  13. +66
    -0
      ports-juce6/roth-air/DspFilters/Common.h
  14. +177
    -0
      ports-juce6/roth-air/DspFilters/Custom.h
  15. +64
    -0
      ports-juce6/roth-air/DspFilters/Design.h
  16. +62
    -0
      ports-juce6/roth-air/DspFilters/Dsp.h
  17. +359
    -0
      ports-juce6/roth-air/DspFilters/Elliptic.h
  18. +269
    -0
      ports-juce6/roth-air/DspFilters/Filter.h
  19. +170
    -0
      ports-juce6/roth-air/DspFilters/Layout.h
  20. +417
    -0
      ports-juce6/roth-air/DspFilters/Legendre.h
  21. +154
    -0
      ports-juce6/roth-air/DspFilters/MathSupplement.h
  22. +244
    -0
      ports-juce6/roth-air/DspFilters/Params.h
  23. +217
    -0
      ports-juce6/roth-air/DspFilters/PoleFilter.h
  24. +335
    -0
      ports-juce6/roth-air/DspFilters/RBJ.h
  25. +129
    -0
      ports-juce6/roth-air/DspFilters/RootFinder.h
  26. +155
    -0
      ports-juce6/roth-air/DspFilters/SmoothedFilter.h
  27. +323
    -0
      ports-juce6/roth-air/DspFilters/State.h
  28. +139
    -0
      ports-juce6/roth-air/DspFilters/Types.h
  29. +730
    -0
      ports-juce6/roth-air/DspFilters/Utilities.h
  30. +224
    -0
      ports-juce6/roth-air/DspFilters/source/Bessel.cpp
  31. +236
    -0
      ports-juce6/roth-air/DspFilters/source/Biquad.cpp
  32. +212
    -0
      ports-juce6/roth-air/DspFilters/source/Butterworth.cpp
  33. +118
    -0
      ports-juce6/roth-air/DspFilters/source/Cascade.cpp
  34. +272
    -0
      ports-juce6/roth-air/DspFilters/source/ChebyshevI.cpp
  35. +271
    -0
      ports-juce6/roth-air/DspFilters/source/ChebyshevII.cpp
  36. +66
    -0
      ports-juce6/roth-air/DspFilters/source/Custom.cpp
  37. +41
    -0
      ports-juce6/roth-air/DspFilters/source/Design.cpp
  38. +456
    -0
      ports-juce6/roth-air/DspFilters/source/Documentation.cpp
  39. +384
    -0
      ports-juce6/roth-air/DspFilters/source/Elliptic.cpp
  40. +117
    -0
      ports-juce6/roth-air/DspFilters/source/Filter.cpp
  41. +344
    -0
      ports-juce6/roth-air/DspFilters/source/Legendre.cpp
  42. +309
    -0
      ports-juce6/roth-air/DspFilters/source/Param.cpp
  43. +337
    -0
      ports-juce6/roth-air/DspFilters/source/PoleFilter.cpp
  44. +207
    -0
      ports-juce6/roth-air/DspFilters/source/RBJ.cpp
  45. +188
    -0
      ports-juce6/roth-air/DspFilters/source/RootFinder.cpp
  46. +43
    -0
      ports-juce6/roth-air/DspFilters/source/State.cpp
  47. BIN
      ports-juce6/roth-air/Graphics/airText.png
  48. BIN
      ports-juce6/roth-air/Graphics/bigKnob.png
  49. BIN
      ports-juce6/roth-air/Graphics/bigKnob_light.png
  50. BIN
      ports-juce6/roth-air/Graphics/bigKnob_red.png
  51. BIN
      ports-juce6/roth-air/Graphics/label_freq.png
  52. BIN
      ports-juce6/roth-air/Graphics/label_gain.png
  53. BIN
      ports-juce6/roth-air/Graphics/label_mix.png
  54. BIN
      ports-juce6/roth-air/Graphics/label_thresh.png
  55. BIN
      ports-juce6/roth-air/Graphics/smallKnob.png
  56. BIN
      ports-juce6/roth-air/Graphics/smallKnob_light.png
  57. BIN
      ports-juce6/roth-air/Graphics/title.png
  58. BIN
      ports-juce6/roth-air/Graphics/website.png
  59. +33
    -0
      ports-juce6/roth-air/JuceHeader.h
  60. +151
    -0
      ports-juce6/roth-air/JucePluginCharacteristics.h
  61. +621
    -0
      ports-juce6/roth-air/LICENSE
  62. +289
    -0
      ports-juce6/roth-air/PluginEditor.cpp
  63. +171
    -0
      ports-juce6/roth-air/PluginEditor.h
  64. +439
    -0
      ports-juce6/roth-air/PluginProcessor.cpp
  65. +143
    -0
      ports-juce6/roth-air/PluginProcessor.h
  66. +8
    -0
      ports-juce6/roth-air/README.md
  67. +312
    -0
      ports-juce6/roth-air/SideChain.cpp
  68. +81
    -0
      ports-juce6/roth-air/SideChain.h
  69. +57
    -0
      ports-juce6/roth-air/WaveShaper.cpp
  70. +37
    -0
      ports-juce6/roth-air/WaveShaper.h
  71. +21
    -0
      ports-juce6/roth-air/meson.build

+ 1
- 0
meson_options.txt View File

@@ -102,6 +102,7 @@ option('plugins',
'vex',
'wolpertinger',
# juce6
'roth-air',
'swankyamp',
'vitalium',
],


+ 1
- 0
ports-juce6/meson.build View File

@@ -8,6 +8,7 @@ if linux_embed
else
plugins = [
'chow',
'roth-air',
'vitalium',
'swankyamp',
]


+ 4945
- 0
ports-juce6/roth-air/BinaryData.cpp
File diff suppressed because it is too large
View File


+ 63
- 0
ports-juce6/roth-air/BinaryData.h View File

@@ -0,0 +1,63 @@
/* =========================================================================================
This is an auto-generated file: Any edits you make may be overwritten!
*/
#pragma once
namespace BinaryData
{
extern const char* airText_png;
const int airText_pngSize = 22392;
extern const char* bigKnob_light_png;
const int bigKnob_light_pngSize = 60475;
extern const char* bigKnob_red_png;
const int bigKnob_red_pngSize = 38916;
extern const char* bigKnob_png;
const int bigKnob_pngSize = 47504;
extern const char* label_freq_png;
const int label_freq_pngSize = 21456;
extern const char* label_gain_png;
const int label_gain_pngSize = 21661;
extern const char* label_mix_png;
const int label_mix_pngSize = 21577;
extern const char* label_thresh_png;
const int label_thresh_pngSize = 21704;
extern const char* smallKnob_light_png;
const int smallKnob_light_pngSize = 31141;
extern const char* smallKnob_png;
const int smallKnob_pngSize = 31445;
extern const char* title_png;
const int title_pngSize = 24948;
extern const char* website_png;
const int website_pngSize = 23975;
// Number of elements in the namedResourceList and originalFileNames arrays.
const int namedResourceListSize = 12;
// Points to the start of a list of resource names.
extern const char* namedResourceList[];
// Points to the start of a list of resource filenames.
extern const char* originalFilenames[];
// If you provide the name of one of the binary resource variables above, this function will
// return the corresponding data and its size (or a null pointer if the name isn't found).
const char* getNamedResource (const char* resourceNameUTF8, int& dataSizeInBytes);
// If you provide the name of one of the binary resource variables above, this function will
// return the corresponding original, non-mangled filename (or a null pointer if the name isn't found).
const char* getNamedResourceOriginalFilename (const char* resourceNameUTF8);
}

+ 295
- 0
ports-juce6/roth-air/Compressor.cpp View File

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

Compressor
==========
A simple feed forward compressor for use in AIR plugin
A simplified implementation of Martin Zuther's "Squeezer" with some modifications
https://github.com/mzuther/Squeezer

-----------------------------------------------------*/

#include <float.h>
#include "Compressor.h"

//====================================================

Compressor::Compressor(int channels, int sample_rate) :
// Set de-normalization params to float and double absolute minimum
fDeNormal(FLT_MIN),
dDeNormal(DBL_MIN),
dBufferLength(0.1),
nChannels(channels),
nSampleRate(sample_rate)
{
jassert((channels == 1) || (channels == 2));

bufInputSamples.clear();
bufSideChainSamples.clear();
bufOutputSamples.clear();

bufInputSamples.setSize(nChannels, 1);
bufSideChainSamples.setSize(nChannels, 1);
bufOutputSamples.setSize(nChannels, 1);
dCrestFactor = 20.0;
dReleaseCoefLinear = 26 * dBufferLength / 3.0;
setMakeupGain(0.0);
// Clear the sidechain array in case of junk
p_arrSideChain.clear();

// Add sidechain objects and add an entry for each channel into the sample buffers
for (int nChannel = 0; nChannel < 2; ++nChannel)
{
// Make a new sidechain element for each channel
p_arrSideChain.add(new SideChain(nSampleRate));
}
}

Compressor::~Compressor() {

}

double Compressor::getDetectorRmsFilter()
/* Get current detector RMS rate.

return value (double): returns current detector RMS rate*/
{
return p_arrSideChain[0]->getDetectorRmsFilter();
}

void Compressor::setDetectorRmsFilter(double dDetectorRateMsNew)
/* Set new detector RMS rate.

dDetectorRateMsNew (double): new detector RMS filter rate

return value: none*/
{
for (int nChannel = 0; nChannel < nChannels; ++nChannel)
{
p_arrSideChain[nChannel]->setDetectorRmsFilter(dDetectorRateMsNew);
}
}

double Compressor::getThreshold()
/* Get current threshold

return value (double): current threshold in dB*/
{
return p_arrSideChain[0]->getThreshold();
}

void Compressor::setThreshold(double dThresholdNew)
/* Set new threshold.

dThresholdNew (double): new threshold in dB

return value: none*/
{
for (int nChannel = 0; nChannel < nChannels; ++nChannel)
{
p_arrSideChain[nChannel]->setThreshold(dThresholdNew);
}
}

double Compressor::getRatio()
/* Get current comp ratio.

return value (double): returns current ratio*/
{
double dRatioNew = p_arrSideChain[0]->getRatio();

return dRatioNew;
}

void Compressor::setRatio(double dRatioNew)
/* Set new ratio.

dRatioNew (double): new ratio

return value: none*/
{
for (int nChannel = 0; nChannel < nChannels; ++nChannel)
{
p_arrSideChain[nChannel]->setRatio(dRatioNew);
}
}

int Compressor::getAttackRate()
/* Get current attack rate.

return value (int): returns the current attack rate in ms*/
{
return p_arrSideChain[0]->getAttackRate();
}

void Compressor::setAttackRate(int nAttackRateNew)
/* Set new attack rate.

nAttackRateNew (int): new attack rate in ms

return value: none*/
{
for (int nChannel = 0; nChannel < nChannels; ++nChannel)
{
p_arrSideChain[nChannel]->setAttackRate(nAttackRateNew);
}
}

int Compressor::getReleaseRate()
/* Get current release rate.

return value (int): returns the current release rate in ms*/
{
return p_arrSideChain[0]->getReleaseRate();
}

void Compressor::setReleaseRate(int nReleaseRateNew)
/* Set new release rate.

nReleaseRateNew (int): new release rate in ms

return value: none*/
{
for (int nChannel = 0; nChannel < nChannels; ++nChannel)
{
p_arrSideChain[nChannel]->setReleaseRate(nReleaseRateNew);
}
}

double Compressor::getMakeupGain()
/* Get current make-up gain.

return value (double): current make-up gain in dB*/
{
return dMakeupGainDb;
}

void Compressor::setMakeupGain(double dMakeupGainNew)
/* Set new make-up gain.

nMakeupGainNew (double): new makeup gain in dB
return value: none*/
{
dMakeupGainDb = dMakeupGainNew;
dMakeupGain = SideChain::dbtolvl(dMakeupGainDb);
}

double Compressor::getGainReduction(int nChannel)
/* Get current gain reduction.

nChannel (int): queried audio channel
return value (double): returns current gain reduction in dB*/
{
jassert(nChannel >= 0);
jassert(nChannel < nChannels);

return arrGainReduction[nChannel];
}

double Compressor::getGainReductionPeak(int nChannel)
/* Get current peak gain reduction

nChannel (int): queried audio channel
return value (double): returns current peak gain reduction in dB*/
{
jassert(nChannel >= 0);
jassert(nChannel < nChannels);

return arrGainReductionPeak[nChannel];
}

double Compressor::getSampleRate()
{
return p_arrSideChain[0]->getSampleRate();
}

void Compressor::setSampleRate(double newSampleRate)
{
if (newSampleRate != p_arrSideChain[0]->getSampleRate())
{
for (int nChannel = 0; nChannel < nChannels; ++nChannel)
{
p_arrSideChain[nChannel]->setSampleRate(newSampleRate);
}

nSampleRate = (int)newSampleRate;
}
}

void Compressor::resetSideChain() {
for (int nChannel = 0; nChannel < 2; ++nChannel)
{
p_arrSideChain[nChannel]->reset();
}
}

double Compressor::getTempGainReduction()
{
return tempGainReduction;
}

void Compressor::processBlock(AudioBuffer<float> &buffer)
{
int nNumSamples = buffer.getNumSamples();

// Loop through samples
for (int nSample = 0; nSample < nNumSamples; ++nSample)
{
// Get input samples, de-normalize and store in buffer
for (int nChannel = 0; nChannel < nChannels; ++nChannel)
{
// Get current input sample (both as float and as double)
float fInputSample = buffer.getSample(nChannel, nSample);
double dInputSample = (double) fInputSample;

// Remove denormal numbers input samples
fInputSample += fDeNormal;
dInputSample += dDeNormal;
fInputSample -= fDeNormal;
dInputSample -= dDeNormal;

// jassert(arrInputSamples.size() == 2 && arrSidechainSamples.size() == 2 && arrOutputSamples.size() == 2);

// Store de-normalized input sample
// arrInputSamples.set(nChannel, dInputSample);
bufInputSamples.setSample(nChannel, 0, dInputSample);

// Process each channel instead of stereo linking (for channel compability)
// arrSidechainSamples.set(nChannel, arrInputSamples[nChannel]);
bufSideChainSamples.setSample(nChannel, 0, bufInputSamples.getSample(nChannel, 0));

// Calculate level of sidechain sample
double dSideChainInputLevel = SideChain::lvltodb(fabs(bufSideChainSamples.getSample(nChannel, 0)));

// Apply crest factor
dSideChainInputLevel += dCrestFactor;

// Send current input sample to gain reduction
p_arrSideChain[nChannel]->processSample(dSideChainInputLevel);

// Store gain reduction (might only be for metering)
// arrGainReduction.set(nChannel, p_arrSideChain[nChannel]->getGainReduction());

// Apply gain reduction to current input sample
double dGainReduction = p_arrSideChain[nChannel]->getGainReduction();
tempGainReduction = dGainReduction;

// arrOutputSamples.set(nChannel, arrInputSamples[nChannel] / SideChain::dbtolvl(dGainReduction));
bufOutputSamples.setSample(nChannel, 0, bufInputSamples.getSample(nChannel, 0) / SideChain::dbtolvl(dGainReduction));

// arrOutputSamples.set(nChannel, arrOutputSamples[nChannel] * dMakeupGain);
bufOutputSamples.setSample(nChannel, 0, bufOutputSamples.getSample(nChannel, 0) * dMakeupGain);

// Set sample to output buffer
// float fOutput = arrOutputSamples[nChannel];
float fOutput = bufOutputSamples.getSample(nChannel, 0);
buffer.setSample(nChannel, nSample, fOutput);
}
}
}

+ 103
- 0
ports-juce6/roth-air/Compressor.h View File

@@ -0,0 +1,103 @@
/*---------------------------------------------------
Compressor
==========
A simple feed forward compressor for use in AIR plugin
A simplified implementation of Martin Zuther's "Squeezer" with some modifications
https://github.com/mzuther/Squeezer
-----------------------------------------------------*/

#ifndef __COMPRESSOR_H__
#define __COMPRESSOR_H__

class SideChain;

#include "JuceHeader.h"
#include "SideChain.h"

//=============================================================
class Compressor
{
public:
//=========================================================

// Constructor
Compressor(int channels, int sample_rate);
~Compressor();

// Declare functions for setting/getting comp parameters
double getDetectorRmsFilter();
void setDetectorRmsFilter(double dDetectorRateMsNew);

double getThreshold();
void setThreshold(double dThresholdNew);

double getRatio();
void setRatio(double dRatioNew);

int getAttackRate();
void setAttackRate(int nAttackRateNew);

int getReleaseRate();
void setReleaseRate(int nReleaseRateNew);

double getMakeupGain();
void setMakeupGain(double dMakeupGainNew);

double getGainReduction(int nChannel);
double getGainReductionPeak(int nChannel);
double getSampleRate();
void setSampleRate(double newSampleRate);
void resetSideChain();

double getTempGainReduction();

// Declare function for processing audio
void processBlock(AudioBuffer<float> &buffer);

private:
// Declare de-normalization variables
const float fDeNormal;
const double dDeNormal;
const double dBufferLength;

// Variables for keeping track of channels and sample rate
int nChannels;
int nSampleRate;

// Arrays for holding sample data
OwnedArray<SideChain> p_arrSideChain;

// Array<double> arrInputSamples;
// Array<double> arrSidechainSamples;
// Array<double> arrOutputSamples;

AudioSampleBuffer bufInputSamples;
AudioSampleBuffer bufSideChainSamples;
AudioSampleBuffer bufOutputSamples;

Array<double> arrGainReduction;
Array<double> arrGainReductionPeak;

AudioSampleBuffer bufGainReduction;
AudioSampleBuffer bufGainReductionPeak;

double dCrestFactor;

double dReleaseCoefLinear;

// Makeup gain variables
double dMakeupGain;
double dMakeupGainDb;

// Might also need this
double dGainNormalize;

double tempGainReduction;
};

#endif // __COMRESSOR_H__

+ 485
- 0
ports-juce6/roth-air/DspFilters/Bessel.h View File

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

"A Collection of Useful C++ Classes for Digital Signal Processing"
By Vincent Falco

Official project location:
http://code.google.com/p/dspfilterscpp/

See Documentation.cpp for contact information, notes, and bibliography.

--------------------------------------------------------------------------------

License: MIT License (http://www.opensource.org/licenses/mit-license.php)
Copyright (c) 2009 by Vincent Falco

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.

*******************************************************************************/

#ifndef DSPFILTERS_BESSEL_H
#define DSPFILTERS_BESSEL_H

#include "DspFilters/Common.h"
#include "DspFilters/Cascade.h"
#include "DspFilters/Design.h"
#include "DspFilters/Filter.h"
#include "DspFilters/PoleFilter.h"
#include "DspFilters/RootFinder.h"

namespace Dsp {

/*
* Filters with Bessel response characteristics
*
*/

namespace Bessel {

// A Workspace is necessary to find roots

struct WorkspaceBase
{
WorkspaceBase (RootFinderBase* rootsBase)
: roots (*rootsBase)
{
}

RootFinderBase& roots;

private:
WorkspaceBase (WorkspaceBase&);
WorkspaceBase& operator= (WorkspaceBase&);
};

template <int MaxOrder>
struct Workspace : WorkspaceBase
{
Workspace ()
: WorkspaceBase (&m_roots)
{
}

private:
RootFinder <MaxOrder> m_roots;
};

//------------------------------------------------------------------------------

// Half-band analog prototypes (s-plane)

class AnalogLowPass : public LayoutBase
{
public:
AnalogLowPass ();

void design (const int numPoles,
WorkspaceBase* w);

private:
int m_numPoles;
};

//------------------------------------------------------------------------------

class AnalogLowShelf : public LayoutBase
{
public:
AnalogLowShelf ();

void design (int numPoles,
double gainDb,
WorkspaceBase* w);

private:
int m_numPoles;
double m_gainDb;
};

//------------------------------------------------------------------------------

// Factored implementations to reduce template instantiations

struct LowPassBase : PoleFilterBase <AnalogLowPass>
{
void setup (int order,
double sampleRate,
double cutoffFrequency,
WorkspaceBase* w);
};

struct HighPassBase : PoleFilterBase <AnalogLowPass>
{
void setup (int order,
double sampleRate,
double cutoffFrequency,
WorkspaceBase* w);
};

struct BandPassBase : PoleFilterBase <AnalogLowPass>
{
void setup (int order,
double sampleRate,
double centerFrequency,
double widthFrequency,
WorkspaceBase* w);
};

struct BandStopBase : PoleFilterBase <AnalogLowPass>
{
void setup (int order,
double sampleRate,
double centerFrequency,
double widthFrequency,
WorkspaceBase* w);
};

struct LowShelfBase : PoleFilterBase <AnalogLowShelf>
{
void setup (int order,
double sampleRate,
double cutoffFrequency,
double gainDb,
WorkspaceBase* w);
};

//------------------------------------------------------------------------------

//
// Raw filters
//

template <int MaxOrder>
struct LowPass : PoleFilter <LowPassBase, MaxOrder>
{
void setup (int order,
double sampleRate,
double cutoffFrequency)
{
Workspace <MaxOrder> w;
LowPassBase::setup (order,
sampleRate,
cutoffFrequency,
&w);
}
};

template <int MaxOrder>
struct HighPass : PoleFilter <HighPassBase, MaxOrder>
{
void setup (int order,
double sampleRate,
double cutoffFrequency)
{
Workspace <MaxOrder> w;
HighPassBase::setup (order,
sampleRate,
cutoffFrequency,
&w);
}
};

template <int MaxOrder>
struct BandPass : PoleFilter <BandPassBase, MaxOrder, MaxOrder*2>
{
void setup (int order,
double sampleRate,
double centerFrequency,
double widthFrequency)
{
Workspace <MaxOrder> w;
BandPassBase::setup (order,
sampleRate,
centerFrequency,
widthFrequency,
&w);
}
};

template <int MaxOrder>
struct BandStop : PoleFilter <BandStopBase, MaxOrder, MaxOrder*2>
{
void setup (int order,
double sampleRate,
double centerFrequency,
double widthFrequency)
{
Workspace <MaxOrder> w;
BandStopBase::setup (order,
sampleRate,
centerFrequency,
widthFrequency,
&w);
}
};

template <int MaxOrder>
struct LowShelf : PoleFilter <LowShelfBase, MaxOrder, MaxOrder*2>
{
void setup (int order,
double sampleRate,
double cutoffFrequency,
double gainDb)
{
Workspace <MaxOrder> w;
LowShelfBase::setup (order,
sampleRate,
cutoffFrequency,
gainDb,
&w);
}
};

//------------------------------------------------------------------------------

//
// Gui-friendly Design layer
//

namespace Design {

struct TypeIBase : DesignBase
{
enum
{
NumParams = 3
};

static int getNumParams ()
{
return 3;
}

static const ParamInfo getParamInfo_2 ()
{
return ParamInfo::defaultCutoffFrequencyParam ();
}
};

template <class FilterClass>
struct TypeI : TypeIBase, FilterClass
{
void setParams (const Params& params)
{
FilterClass::setup (int(params[1]), params[0], params[2]);
}
};

struct TypeIIBase : DesignBase
{
enum
{
NumParams = 4
};

static int getNumParams ()
{
return 4;
}

static const ParamInfo getParamInfo_2 ()
{
return ParamInfo::defaultCenterFrequencyParam ();
}

static const ParamInfo getParamInfo_3 ()
{
return ParamInfo::defaultBandwidthHzParam ();
}
};

template <class FilterClass>
struct TypeII : TypeIIBase, FilterClass
{
void setParams (const Params& params)
{
FilterClass::setup (int(params[1]), params[0], params[2], params[3]);
}
};

struct TypeIIIBase : DesignBase
{
enum
{
NumParams = 4
};

static int getNumParams ()
{
return 4;
}

static const ParamInfo getParamInfo_2 ()
{
return ParamInfo::defaultCutoffFrequencyParam ();
}

static const ParamInfo getParamInfo_3 ()
{
return ParamInfo::defaultGainParam ();
}
};

template <class FilterClass>
struct TypeIII : TypeIIIBase, FilterClass
{
void setParams (const Params& params)
{
FilterClass::setup (int(params[1]),
params[0],
params[2],
params[3]);
}
};

struct TypeIVBase : DesignBase
{
enum
{
NumParams = 5
};

static int getNumParams ()
{
return 5;
}

static const ParamInfo getParamInfo_2 ()
{
return ParamInfo::defaultCenterFrequencyParam ();
}

static const ParamInfo getParamInfo_3 ()
{
return ParamInfo::defaultBandwidthHzParam ();
}

static const ParamInfo getParamInfo_4 ()
{
return ParamInfo::defaultGainParam ();
}
};

template <class FilterClass>
struct TypeIV : TypeIVBase, FilterClass
{
void setParams (const Params& params)
{
FilterClass::setup (int(params[1]), params[0], params[2], params[3], params[4]);
}
};

// Factored kind and name

struct LowPassDescription
{
static Kind getKind () { return kindLowPass; }
static const char* getName() { return "Bessel Low Pass"; }
};

struct HighPassDescription
{
static Kind getKind () { return kindHighPass; }
static const char* getName() { return "Bessel High Pass"; }
};

struct BandPassDescription
{
static Kind getKind () { return kindHighPass; }
static const char* getName() { return "Bessel Band Pass"; }
};

struct BandStopDescription
{
static Kind getKind () { return kindHighPass; }
static const char* getName() { return "Bessel Band Stop"; }
};

struct LowShelfDescription
{
static Kind getKind () { return kindLowShelf; }
static const char* getName() { return "Bessel Low Shelf"; }
};

// This glues on the Order parameter
template <int MaxOrder,
template <class> class TypeClass,
template <int> class FilterClass>
struct OrderBase : TypeClass <FilterClass <MaxOrder> >
{
const ParamInfo getParamInfo_1 () const
{
return ParamInfo (idOrder, "Order", "Order",
1, MaxOrder, 2,
&ParamInfo::Int_toControlValue,
&ParamInfo::Int_toNativeValue,
&ParamInfo::Int_toString);

}
};

//------------------------------------------------------------------------------

//
// Gui-friendly Design layer
//

template <int MaxOrder>
struct LowPass : OrderBase <MaxOrder, TypeI, Bessel::LowPass>,
LowPassDescription
{
};

template <int MaxOrder>
struct HighPass : OrderBase <MaxOrder, TypeI, Bessel::HighPass>,
HighPassDescription
{
};

template <int MaxOrder>
struct BandPass : OrderBase <MaxOrder, TypeII, Bessel::BandPass>,
BandPassDescription
{
};

template <int MaxOrder>
struct BandStop : OrderBase <MaxOrder, TypeII, Bessel::BandStop>,
BandStopDescription
{
};

/*
* NOT IMPLEMENTED
*
*/
template <int MaxOrder>
struct LowShelf : OrderBase <MaxOrder, TypeIII, Bessel::LowShelf>,
LowShelfDescription
{
};

}

}

}

#endif

/* This is a test of svn:external */

+ 232
- 0
ports-juce6/roth-air/DspFilters/Biquad.h View File

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

"A Collection of Useful C++ Classes for Digital Signal Processing"
By Vincent Falco

Official project location:
http://code.google.com/p/dspfilterscpp/

See Documentation.cpp for contact information, notes, and bibliography.

--------------------------------------------------------------------------------

License: MIT License (http://www.opensource.org/licenses/mit-license.php)
Copyright (c) 2009 by Vincent Falco

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.

*******************************************************************************/

#ifndef DSPFILTERS_BIQUAD_H
#define DSPFILTERS_BIQUAD_H

#include "DspFilters/Common.h"
#include "DspFilters/MathSupplement.h"
#include "DspFilters/Types.h"

namespace Dsp {

struct BiquadPoleState;

/*
* Holds coefficients for a second order Infinite Impulse Response
* digital filter. This is the building block for all IIR filters.
*
*/

// Factored interface to prevent outsiders from fiddling
class BiquadBase
{
public:
template <class StateType>
struct State : StateType, private DenormalPrevention
{
template <typename Sample>
inline Sample process (const Sample in, const BiquadBase& b)
{
return static_cast<Sample> (StateType::process1 (in, b, ac()));
}
};

public:
// Calculate filter response at the given normalized frequency.
complex_t response (double normalizedFrequency) const;

std::vector<PoleZeroPair> getPoleZeros () const;

double getA0 () const { return m_a0; }
double getA1 () const { return m_a1*m_a0; }
double getA2 () const { return m_a2*m_a0; }
double getB0 () const { return m_b0*m_a0; }
double getB1 () const { return m_b1*m_a0; }
double getB2 () const { return m_b2*m_a0; }

// Process a block of samples in the given form
template <class StateType, typename Sample>
void process (int numSamples, Sample* dest, StateType& state) const
{
while (--numSamples >= 0)
*dest++ = state.process (*dest, *this);
}

protected:
//
// These are protected so you can't mess with RBJ biquads
//

void setCoefficients (double a0, double a1, double a2,
double b0, double b1, double b2);

void setOnePole (complex_t pole, complex_t zero);

void setTwoPole (complex_t pole1, complex_t zero1,
complex_t pole2, complex_t zero2);

void setPoleZeroPair (const PoleZeroPair& pair)
{
if (pair.isSinglePole ())
setOnePole (pair.poles.first, pair.zeros.first);
else
setTwoPole (pair.poles.first, pair.zeros.first,
pair.poles.second, pair.zeros.second);
}

void setPoleZeroForm (const BiquadPoleState& bps);

void setIdentity ();

void applyScale (double scale);

public:
double m_a0;
double m_a1;
double m_a2;
double m_b1;
double m_b2;
double m_b0;
};

//------------------------------------------------------------------------------

// Expresses a biquad as a pair of pole/zeros, with gain
// values so that the coefficients can be reconstructed precisely.
struct BiquadPoleState : PoleZeroPair
{
BiquadPoleState () { }

explicit BiquadPoleState (const BiquadBase& s);

double gain;
};

// More permissive interface for fooling around
class Biquad : public BiquadBase
{
public:
Biquad ();

explicit Biquad (const BiquadPoleState& bps);

public:
// Process a block of samples, interpolating from the old section's coefficients
// to this section's coefficients, over numSamples. This implements smooth
// parameter changes.

template <class StateType, typename Sample>
void smoothProcess1 (int numSamples,
Sample* dest,
StateType& state,
Biquad sectionPrev) const
{
double t = 1. / numSamples;
double da1 = (m_a1 - sectionPrev.m_a1) * t;
double da2 = (m_a2 - sectionPrev.m_a2) * t;
double db0 = (m_b0 - sectionPrev.m_b0) * t;
double db1 = (m_b1 - sectionPrev.m_b1) * t;
double db2 = (m_b2 - sectionPrev.m_b2) * t;

while (--numSamples >= 0)
{
sectionPrev.m_a1 += da1;
sectionPrev.m_a2 += da2;
sectionPrev.m_b0 += db0;
sectionPrev.m_b1 += db1;
sectionPrev.m_b2 += db2;

*dest++ = state.process (*dest, sectionPrev);
}
}

// Process a block of samples, interpolating from the old section's pole/zeros
// to this section's pole/zeros, over numSamples. The interpolation is done
// in the z-plane using polar coordinates.
template <class StateType, typename Sample>
void smoothProcess2 (int numSamples,
Sample* dest,
StateType& state,
BiquadPoleState zPrev) const
{
BiquadPoleState z (*this);
double t = 1. / numSamples;
complex_t dp0 = (z.poles.first - zPrev.poles.first) * t;
complex_t dp1 = (z.poles.second - zPrev.poles.second) * t;
complex_t dz0 = (z.zeros.first - zPrev.zeros.first) * t;
complex_t dz1 = (z.zeros.second - zPrev.zeros.second) * t;
double dg = (z.gain - zPrev.gain) * t;

while (--numSamples >= 0)
{
zPrev.poles.first += dp0;
zPrev.poles.second += dp1;
zPrev.zeros.first += dz0;
zPrev.zeros.second += dz1;
zPrev.gain += dg;

*dest++ = state.process (*dest, Biquad (zPrev));
}
}

public:
// Export these as public

void setOnePole (complex_t pole, complex_t zero)
{
BiquadBase::setOnePole (pole, zero);
}

void setTwoPole (complex_t pole1, complex_t zero1,
complex_t pole2, complex_t zero2)
{
BiquadBase::setTwoPole (pole1, zero1, pole2, zero2);
}

void setPoleZeroPair (const PoleZeroPair& pair)
{
BiquadBase::setPoleZeroPair (pair);
}

void applyScale (double scale)
{
BiquadBase::applyScale (scale);
}
};

}

#endif

+ 436
- 0
ports-juce6/roth-air/DspFilters/Butterworth.h View File

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

"A Collection of Useful C++ Classes for Digital Signal Processing"
By Vincent Falco

Official project location:
http://code.google.com/p/dspfilterscpp/

See Documentation.cpp for contact information, notes, and bibliography.

--------------------------------------------------------------------------------

License: MIT License (http://www.opensource.org/licenses/mit-license.php)
Copyright (c) 2009 by Vincent Falco

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.

*******************************************************************************/

#ifndef DSPFILTERS_BUTTERWORTH_H
#define DSPFILTERS_BUTTERWORTH_H

#include "DspFilters/Common.h"
#include "DspFilters/Cascade.h"
#include "DspFilters/Design.h"
#include "DspFilters/Filter.h"
#include "DspFilters/PoleFilter.h"

namespace Dsp {

/*
* Filters with Butterworth response characteristics
*
*/

namespace Butterworth {

// Half-band analog prototypes (s-plane)

class AnalogLowPass : public LayoutBase
{
public:
AnalogLowPass ();

void design (const int numPoles);

private:
int m_numPoles;
};

//------------------------------------------------------------------------------

class AnalogLowShelf : public LayoutBase
{
public:
AnalogLowShelf ();

void design (int numPoles, double gainDb);

private:
int m_numPoles;
double m_gainDb;
};

//------------------------------------------------------------------------------

// Factored implementations to reduce template instantiations

struct LowPassBase : PoleFilterBase <AnalogLowPass>
{
void setup (int order,
double sampleRate,
double cutoffFrequency);
};

struct HighPassBase : PoleFilterBase <AnalogLowPass>
{
void setup (int order,
double sampleRate,
double cutoffFrequency);
};

struct BandPassBase : PoleFilterBase <AnalogLowPass>
{
void setup (int order,
double sampleRate,
double centerFrequency,
double widthFrequency);
};

struct BandStopBase : PoleFilterBase <AnalogLowPass>
{
void setup (int order,
double sampleRate,
double centerFrequency,
double widthFrequency);
};

struct LowShelfBase : PoleFilterBase <AnalogLowShelf>
{
void setup (int order,
double sampleRate,
double cutoffFrequency,
double gainDb);
};

struct HighShelfBase : PoleFilterBase <AnalogLowShelf>
{
void setup (int order,
double sampleRate,
double cutoffFrequency,
double gainDb);
};

struct BandShelfBase : PoleFilterBase <AnalogLowShelf>
{
void setup (int order,
double sampleRate,
double centerFrequency,
double widthFrequency,
double gainDb);
};

//------------------------------------------------------------------------------

//
// Raw filters
//

template <int MaxOrder>
struct LowPass : PoleFilter <LowPassBase, MaxOrder>
{
};

template <int MaxOrder>
struct HighPass : PoleFilter <HighPassBase, MaxOrder>
{
};

template <int MaxOrder>
struct BandPass : PoleFilter <BandPassBase, MaxOrder, MaxOrder*2>
{
};

template <int MaxOrder>
struct BandStop : PoleFilter <BandStopBase, MaxOrder, MaxOrder*2>
{
};

template <int MaxOrder>
struct LowShelf : PoleFilter <LowShelfBase, MaxOrder>
{
};

template <int MaxOrder>
struct HighShelf : PoleFilter <HighShelfBase, MaxOrder>
{
};

template <int MaxOrder>
struct BandShelf : PoleFilter <BandShelfBase, MaxOrder, MaxOrder*2>
{
};

//------------------------------------------------------------------------------

//
// Gui-friendly Design layer
//

namespace Design {

struct TypeIBase : DesignBase
{
enum
{
NumParams = 3
};

static int getNumParams ()
{
return 3;
}

static const ParamInfo getParamInfo_2 ()
{
return ParamInfo::defaultCutoffFrequencyParam ();
}
};

template <class FilterClass>
struct TypeI : TypeIBase, FilterClass
{
void setParams (const Params& params)
{
FilterClass::setup (int(params[1]), params[0], params[2]);
}
};

struct TypeIIBase : DesignBase
{
enum
{
NumParams = 4
};

static int getNumParams ()
{
return 4;
}

static const ParamInfo getParamInfo_2 ()
{
return ParamInfo::defaultCenterFrequencyParam ();
}

static const ParamInfo getParamInfo_3 ()
{
return ParamInfo::defaultBandwidthHzParam ();
}
};

template <class FilterClass>
struct TypeII : TypeIIBase, FilterClass
{
void setParams (const Params& params)
{
FilterClass::setup (int(params[1]), params[0], params[2], params[3]);
}
};

struct TypeIIIBase : DesignBase
{
enum
{
NumParams = 4
};

static int getNumParams ()
{
return 4;
}

static const ParamInfo getParamInfo_2 ()
{
return ParamInfo::defaultCutoffFrequencyParam ();
}

static const ParamInfo getParamInfo_3 ()
{
return ParamInfo::defaultGainParam ();
}
};

template <class FilterClass>
struct TypeIII : TypeIIIBase, FilterClass
{
void setParams (const Params& params)
{
FilterClass::setup (int(params[1]),
params[0],
params[2],
params[3]);
}
};

struct TypeIVBase : DesignBase
{
enum
{
NumParams = 5
};

static int getNumParams ()
{
return 5;
}

static const ParamInfo getParamInfo_2 ()
{
return ParamInfo::defaultCenterFrequencyParam ();
}

static const ParamInfo getParamInfo_3 ()
{
return ParamInfo::defaultBandwidthHzParam ();
}

static const ParamInfo getParamInfo_4 ()
{
return ParamInfo::defaultGainParam ();
}
};

template <class FilterClass>
struct TypeIV : TypeIVBase, FilterClass
{
void setParams (const Params& params)
{
FilterClass::setup (int(params[1]), params[0], params[2], params[3], params[4]);
}
};

// Factored kind and name

struct LowPassDescription
{
static Kind getKind () { return kindLowPass; }
static const char* getName() { return "Butterworth Low Pass"; }
};

struct HighPassDescription
{
static Kind getKind () { return kindHighPass; }
static const char* getName() { return "Butterworth High Pass"; }
};

struct BandPassDescription
{
static Kind getKind () { return kindHighPass; }
static const char* getName() { return "Butterworth Band Pass"; }
};

struct BandStopDescription
{
static Kind getKind () { return kindHighPass; }
static const char* getName() { return "Butterworth Band Stop"; }
};

struct LowShelfDescription
{
static Kind getKind () { return kindLowShelf; }
static const char* getName() { return "Butterworth Low Shelf"; }
};

struct HighShelfDescription
{
static Kind getKind () { return kindHighShelf; }
static const char* getName() { return "Butterworth High Shelf"; }
};

struct BandShelfDescription
{
static Kind getKind () { return kindBandShelf; }
static const char* getName() { return "Butterworth Band Shelf"; }
};

// This glues on the Order parameter
template <int MaxOrder,
template <class> class TypeClass,
template <int> class FilterClass>
struct OrderBase : TypeClass <FilterClass <MaxOrder> >
{
const ParamInfo getParamInfo_1 () const
{
return ParamInfo (idOrder, "Order", "Order",
1, MaxOrder, 2,
&ParamInfo::Int_toControlValue,
&ParamInfo::Int_toNativeValue,
&ParamInfo::Int_toString);

}
};

//------------------------------------------------------------------------------

//
// Design filters
//

template <int MaxOrder>
struct LowPass : OrderBase <MaxOrder, TypeI, Butterworth::LowPass>,
LowPassDescription
{
};

template <int MaxOrder>
struct HighPass : OrderBase <MaxOrder, TypeI, Butterworth::HighPass>,
HighPassDescription
{
};

template <int MaxOrder>
struct BandPass : OrderBase <MaxOrder, TypeII, Butterworth::BandPass>,
BandPassDescription
{
};

template <int MaxOrder>
struct BandStop : OrderBase <MaxOrder, TypeII, Butterworth::BandStop>,
BandStopDescription
{
};

template <int MaxOrder>
struct LowShelf : OrderBase <MaxOrder, TypeIII, Butterworth::LowShelf>,
LowShelfDescription
{
};

template <int MaxOrder>
struct HighShelf : OrderBase <MaxOrder, TypeIII, Butterworth::HighShelf>,
HighShelfDescription
{
};

template <int MaxOrder>
struct BandShelf : OrderBase <MaxOrder, TypeIV, Butterworth::BandShelf>,
BandShelfDescription
{
};

}

}

}

#endif


+ 181
- 0
ports-juce6/roth-air/DspFilters/Cascade.h View File

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

"A Collection of Useful C++ Classes for Digital Signal Processing"
By Vincent Falco

Official project location:
http://code.google.com/p/dspfilterscpp/

See Documentation.cpp for contact information, notes, and bibliography.

--------------------------------------------------------------------------------

License: MIT License (http://www.opensource.org/licenses/mit-license.php)
Copyright (c) 2009 by Vincent Falco

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.

*******************************************************************************/

#ifndef DSPFILTERS_CASCADE_H
#define DSPFILTERS_CASCADE_H

#include "DspFilters/Common.h"
#include "DspFilters/Biquad.h"
#include "DspFilters/Filter.h"
#include "DspFilters/Layout.h"
#include "DspFilters/MathSupplement.h"

namespace Dsp {

/*
* Holds coefficients for a cascade of second order sections.
*
*/

// Factored implementation to reduce template instantiations
class Cascade
{
public:
template <class StateType>
class StateBase : private DenormalPrevention
{
public:
template <typename Sample>
inline Sample process (const Sample in, const Cascade& c)
{
double out = in;
StateType* state = m_stateArray;
Biquad const* stage = c.m_stageArray;
const double vsa = ac();
int i = c.m_numStages - 1;
out = (state++)->process1 (out, *stage++, vsa);
for (; --i >= 0;)
out = (state++)->process1 (out, *stage++, 0);
//for (int i = c.m_numStages; --i >= 0; ++state, ++stage)
// out = state->process1 (out, *stage, vsa);
return static_cast<Sample> (out);
}

protected:
StateBase (StateType* stateArray)
: m_stateArray (stateArray)
{
}

protected:
StateType* m_stateArray;
};

struct Stage : Biquad
{
};

struct Storage
{
Storage (int maxStages_, Stage* stageArray_)
: maxStages (maxStages_)
, stageArray (stageArray_)
{
}

int maxStages;
Stage* stageArray;
};

int getNumStages () const
{
return m_numStages;
}

const Stage& operator[] (int index)
{
assert (index >= 0 && index <= m_numStages);
return m_stageArray[index];
}

public:
// Calculate filter response at the given normalized frequency.
complex_t response (double normalizedFrequency) const;

std::vector<PoleZeroPair> getPoleZeros () const;

// Process a block of samples in the given form
template <class StateType, typename Sample>
void process (int numSamples, Sample* dest, StateType& state) const
{
while (--numSamples >= 0)
*dest++ = state.process (*dest, *this);
}

protected:
Cascade ();

void setCascadeStorage (const Storage& storage);

void applyScale (double scale);
void setLayout (const LayoutBase& proto);

private:
int m_numStages;
int m_maxStages;
Stage* m_stageArray;
};

//------------------------------------------------------------------------------

// Storage for Cascade
template <int MaxStages>
class CascadeStages
{
public:
template <class StateType>
class State : public Cascade::StateBase <StateType>
{
public:
State() : Cascade::StateBase <StateType> (m_states)
{
Cascade::StateBase <StateType>::m_stateArray = m_states;
reset ();
}

void reset ()
{
StateType* state = m_states;
for (int i = MaxStages; --i >= 0; ++state)
state->reset();
}

private:
StateType m_states[MaxStages];
};

/*@Internal*/
Cascade::Storage getCascadeStorage()
{
return Cascade::Storage (MaxStages, m_stages);
}

private:
Cascade::Stage m_stages[MaxStages];
};

}

#endif

+ 465
- 0
ports-juce6/roth-air/DspFilters/ChebyshevI.h View File

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

"A Collection of Useful C++ Classes for Digital Signal Processing"
By Vincent Falco

Official project location:
http://code.google.com/p/dspfilterscpp/

See Documentation.cpp for contact information, notes, and bibliography.

--------------------------------------------------------------------------------

License: MIT License (http://www.opensource.org/licenses/mit-license.php)
Copyright (c) 2009 by Vincent Falco

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.

*******************************************************************************/

#ifndef DSPFILTERS_CHEBYSHEVI_H
#define DSPFILTERS_CHEBYSHEVI_H

#include "DspFilters/Common.h"
#include "DspFilters/Cascade.h"
#include "DspFilters/Design.h"
#include "DspFilters/Filter.h"
#include "DspFilters/PoleFilter.h"

namespace Dsp {

/*
* Filters with Chebyshev response characteristics
*
*/

namespace ChebyshevI {

// Half-band analog prototypes (s-plane)

class AnalogLowPass : public LayoutBase
{
public:
AnalogLowPass ();

void design (const int numPoles,
double rippleDb);

private:
int m_numPoles;
double m_rippleDb;
};

//------------------------------------------------------------------------------

class AnalogLowShelf : public LayoutBase
{
public:
AnalogLowShelf ();

void design (int numPoles,
double gainDb,
double rippleDb);

private:
int m_numPoles;
double m_rippleDb;
double m_gainDb;
};

//------------------------------------------------------------------------------

// Factored implementations to reduce template instantiations

struct LowPassBase : PoleFilterBase <AnalogLowPass>
{
void setup (int order,
double sampleRate,
double cutoffFrequency,
double rippleDb);
};

struct HighPassBase : PoleFilterBase <AnalogLowPass>
{
void setup (int order,
double sampleRate,
double cutoffFrequency,
double rippleDb);
};

struct BandPassBase : PoleFilterBase <AnalogLowPass>
{
void setup (int order,
double sampleRate,
double centerFrequency,
double widthFrequency,
double rippleDb);
};

struct BandStopBase : PoleFilterBase <AnalogLowPass>
{
void setup (int order,
double sampleRate,
double centerFrequency,
double widthFrequency,
double rippleDb);
};

struct LowShelfBase : PoleFilterBase <AnalogLowShelf>
{
void setup (int order,
double sampleRate,
double cutoffFrequency,
double gainDb,
double rippleDb);
};

struct HighShelfBase : PoleFilterBase <AnalogLowShelf>
{
void setup (int order,
double sampleRate,
double cutoffFrequency,
double gainDb,
double rippleDb);
};

struct BandShelfBase : PoleFilterBase <AnalogLowShelf>
{
void setup (int order,
double sampleRate,
double centerFrequency,
double widthFrequency,
double gainDb,
double rippleDb);
};

//------------------------------------------------------------------------------

//
// Raw filters
//

template <int MaxOrder>
struct LowPass : PoleFilter <LowPassBase, MaxOrder>
{
};

template <int MaxOrder>
struct HighPass : PoleFilter <HighPassBase, MaxOrder>
{
};

template <int MaxOrder>
struct BandPass : PoleFilter <BandPassBase, MaxOrder, MaxOrder*2>
{
};

template <int MaxOrder>
struct BandStop : PoleFilter <BandStopBase, MaxOrder, MaxOrder*2>
{
};

template <int MaxOrder>
struct LowShelf : PoleFilter <LowShelfBase, MaxOrder>
{
};

template <int MaxOrder>
struct HighShelf : PoleFilter <HighShelfBase, MaxOrder>
{
};

template <int MaxOrder>
struct BandShelf : PoleFilter <BandShelfBase, MaxOrder, MaxOrder*2>
{
};

//------------------------------------------------------------------------------

//
// Gui-friendly Design layer
//

namespace Design {

struct TypeIBase : DesignBase
{
enum
{
NumParams = 4
};

static int getNumParams ()
{
return 4;
}

static const ParamInfo getParamInfo_2 ()
{
return ParamInfo::defaultCutoffFrequencyParam ();
}

static const ParamInfo getParamInfo_3 ()
{
return ParamInfo::defaultRippleDbParam ();
}
};

template <class FilterClass>
struct TypeI : TypeIBase, FilterClass
{
void setParams (const Params& params)
{
FilterClass::setup (int(params[1]), params[0], params[2], params[3]);
}
};

struct TypeIIBase : DesignBase
{
enum
{
NumParams = 5
};

static int getNumParams ()
{
return 5;
}

static const ParamInfo getParamInfo_2 ()
{
return ParamInfo::defaultCenterFrequencyParam ();
}

static const ParamInfo getParamInfo_3 ()
{
return ParamInfo::defaultBandwidthHzParam ();
}

static const ParamInfo getParamInfo_4 ()
{
return ParamInfo::defaultRippleDbParam ();
}
};

template <class FilterClass>
struct TypeII : TypeIIBase, FilterClass
{
void setParams (const Params& params)
{
FilterClass::setup (int(params[1]), params[0], params[2], params[3], params[4]);
}
};

struct TypeIIIBase : DesignBase
{
enum
{
NumParams = 5
};

static int getNumParams ()
{
return 5;
}

static const ParamInfo getParamInfo_2 ()
{
return ParamInfo::defaultCutoffFrequencyParam ();
}

static const ParamInfo getParamInfo_3 ()
{
return ParamInfo::defaultGainParam ();
}

static const ParamInfo getParamInfo_4 ()
{
return ParamInfo::defaultRippleDbParam ();
}
};

template <class FilterClass>
struct TypeIII : TypeIIIBase, FilterClass
{
void setParams (const Params& params)
{
FilterClass::setup (int(params[1]), params[0], params[2], params[3], params[4]);
}
};

struct TypeIVBase : DesignBase
{
enum
{
NumParams = 6
};

static int getNumParams ()
{
return 6;
}

static const ParamInfo getParamInfo_2 ()
{
return ParamInfo::defaultCenterFrequencyParam ();
}

static const ParamInfo getParamInfo_3 ()
{
return ParamInfo::defaultBandwidthHzParam ();
}

static const ParamInfo getParamInfo_4 ()
{
return ParamInfo::defaultGainParam ();
}

static const ParamInfo getParamInfo_5 ()
{
return ParamInfo::defaultRippleDbParam ();
}
};

template <class FilterClass>
struct TypeIV : TypeIVBase, FilterClass
{
void setParams (const Params& params)
{
FilterClass::setup (int(params[1]), params[0], params[2], params[3], params[4], params[5]);
}
};

// Factored kind and name

struct LowPassDescription
{
static Kind getKind () { return kindLowPass; }
static const char* getName() { return "Chebyshev I Low Pass"; }
};

struct HighPassDescription
{
static Kind getKind () { return kindHighPass; }
static const char* getName() { return "Chebyshev I High Pass"; }
};

struct BandPassDescription
{
static Kind getKind () { return kindHighPass; }
static const char* getName() { return "Chebyshev I Band Pass"; }
};

struct BandStopDescription
{
static Kind getKind () { return kindHighPass; }
static const char* getName() { return "Chebyshev I Band Stop"; }
};

struct LowShelfDescription
{
static Kind getKind () { return kindLowShelf; }
static const char* getName() { return "Chebyshev I Low Shelf"; }
};

struct HighShelfDescription
{
static Kind getKind () { return kindHighShelf; }
static const char* getName() { return "Chebyshev I High Shelf"; }
};

struct BandShelfDescription
{
static Kind getKind () { return kindBandShelf; }
static const char* getName() { return "Chebyshev I Band Shelf"; }
};

// This glues on the Order parameter
template <int MaxOrder,
template <class> class TypeClass,
template <int> class FilterClass>
struct OrderBase : TypeClass <FilterClass <MaxOrder> >
{
const ParamInfo getParamInfo_1 () const
{
return ParamInfo (idOrder, "Order", "Order",
1, MaxOrder, 2,
&ParamInfo::Int_toControlValue,
&ParamInfo::Int_toNativeValue,
&ParamInfo::Int_toString);

}
};

//------------------------------------------------------------------------------

//
// Design filters
//

template <int MaxOrder>
struct LowPass : OrderBase <MaxOrder, TypeI, ChebyshevI::LowPass>,
LowPassDescription
{
};

template <int MaxOrder>
struct HighPass : OrderBase <MaxOrder, TypeI, ChebyshevI::HighPass>,
HighPassDescription
{
};

template <int MaxOrder>
struct BandPass : OrderBase <MaxOrder, TypeII, ChebyshevI::BandPass>,
BandPassDescription
{
};

template <int MaxOrder>
struct BandStop : OrderBase <MaxOrder, TypeII, ChebyshevI::BandStop>,
BandStopDescription
{
};

template <int MaxOrder>
struct LowShelf : OrderBase <MaxOrder, TypeIII, ChebyshevI::LowShelf>,
LowShelfDescription
{
};

template <int MaxOrder>
struct HighShelf : OrderBase <MaxOrder, TypeIII, ChebyshevI::HighShelf>,
HighShelfDescription
{
};

template <int MaxOrder>
struct BandShelf : OrderBase <MaxOrder, TypeIV, ChebyshevI::BandShelf>,
BandShelfDescription
{
};

}

}

}

#endif


+ 466
- 0
ports-juce6/roth-air/DspFilters/ChebyshevII.h View File

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

"A Collection of Useful C++ Classes for Digital Signal Processing"
By Vincent Falco

Official project location:
http://code.google.com/p/dspfilterscpp/

See Documentation.cpp for contact information, notes, and bibliography.

--------------------------------------------------------------------------------

License: MIT License (http://www.opensource.org/licenses/mit-license.php)
Copyright (c) 2009 by Vincent Falco

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.

*******************************************************************************/

#ifndef DSPFILTERS_CHEBYSHEVII_H
#define DSPFILTERS_CHEBYSHEVII_H

#include "DspFilters/Common.h"
#include "DspFilters/Cascade.h"
#include "DspFilters/Design.h"
#include "DspFilters/Filter.h"
#include "DspFilters/PoleFilter.h"

namespace Dsp {

/*
* Filters with Inverse Chebyshev response characteristics
*
*/

namespace ChebyshevII {

// Half-band analog prototypes (s-plane)

class AnalogLowPass : public LayoutBase
{
public:
AnalogLowPass ();

void design (const int numPoles,
double stopBandDb);

private:
int m_numPoles;
double m_stopBandDb;
};

//------------------------------------------------------------------------------

class AnalogLowShelf : public LayoutBase
{
public:
AnalogLowShelf ();

void design (int numPoles,
double gainDb,
double stopBandDb);

private:
int m_numPoles;
double m_stopBandDb;
double m_gainDb;
};

//------------------------------------------------------------------------------

// Factored implementations to reduce template instantiations

struct LowPassBase : PoleFilterBase <AnalogLowPass>
{
void setup (int order,
double sampleRate,
double cutoffFrequency,
double stopBandDb);
};

struct HighPassBase : PoleFilterBase <AnalogLowPass>
{
void setup (int order,
double sampleRate,
double cutoffFrequency,
double stopBandDb);
};

struct BandPassBase : PoleFilterBase <AnalogLowPass>
{
void setup (int order,
double sampleRate,
double centerFrequency,
double widthFrequency,
double stopBandDb);
};

struct BandStopBase : PoleFilterBase <AnalogLowPass>
{
void setup (int order,
double sampleRate,
double centerFrequency,
double widthFrequency,
double stopBandDb);
};

struct LowShelfBase : PoleFilterBase <AnalogLowShelf>
{
void setup (int order,
double sampleRate,
double cutoffFrequency,
double gainDb,
double stopBandDb);
};

struct HighShelfBase : PoleFilterBase <AnalogLowShelf>
{
void setup (int order,
double sampleRate,
double cutoffFrequency,
double gainDb,
double stopBandDb);
};

struct BandShelfBase : PoleFilterBase <AnalogLowShelf>
{
void setup (int order,
double sampleRate,
double centerFrequency,
double widthFrequency,
double gainDb,
double stopBandDb);
};

//------------------------------------------------------------------------------

//
// Raw filters
//

template <int MaxOrder>
struct LowPass : PoleFilter <LowPassBase, MaxOrder>
{
};

template <int MaxOrder>
struct HighPass : PoleFilter <HighPassBase, MaxOrder>
{
};

template <int MaxOrder>
struct BandPass : PoleFilter <BandPassBase, MaxOrder, MaxOrder*2>
{
};

template <int MaxOrder>
struct BandStop : PoleFilter <BandStopBase, MaxOrder, MaxOrder*2>
{
};

template <int MaxOrder>
struct LowShelf : PoleFilter <LowShelfBase, MaxOrder>
{
};

template <int MaxOrder>
struct HighShelf : PoleFilter <HighShelfBase, MaxOrder>
{
};

template <int MaxOrder>
struct BandShelf : PoleFilter <BandShelfBase, MaxOrder, MaxOrder*2>
{
};

//------------------------------------------------------------------------------

//
// Gui-friendly Design layer
//

namespace Design {

struct TypeIBase : DesignBase
{
enum
{
NumParams = 4
};

static int getNumParams ()
{
return 4;
}

static const ParamInfo getParamInfo_2 ()
{
return ParamInfo::defaultCutoffFrequencyParam ();
}

static const ParamInfo getParamInfo_3 ()
{
return ParamInfo::defaultStopDbParam ();
}
};

template <class FilterClass>
struct TypeI : TypeIBase, FilterClass
{
void setParams (const Params& params)
{
FilterClass::setup (int(params[1]), params[0], params[2], params[3]);
}
};

struct TypeIIBase : DesignBase
{
enum
{
NumParams = 5
};

static int getNumParams ()
{
return 5;
}

static const ParamInfo getParamInfo_2 ()
{
return ParamInfo::defaultCenterFrequencyParam ();
}

static const ParamInfo getParamInfo_3 ()
{
return ParamInfo::defaultBandwidthHzParam ();
}

static const ParamInfo getParamInfo_4 ()
{
return ParamInfo::defaultStopDbParam ();
}
};

template <class FilterClass>
struct TypeII : TypeIIBase, FilterClass
{
void setParams (const Params& params)
{
FilterClass::setup (int(params[1]), params[0], params[2], params[3], params[4]);
}
};

struct TypeIIIBase : DesignBase
{
enum
{
NumParams = 5
};

static int getNumParams ()
{
return 5;
}

static const ParamInfo getParamInfo_2 ()
{
return ParamInfo::defaultCutoffFrequencyParam ();
}

static const ParamInfo getParamInfo_3 ()
{
return ParamInfo::defaultGainParam ();
}

static const ParamInfo getParamInfo_4 ()
{
return ParamInfo::defaultStopDbParam ();
}
};

template <class FilterClass>
struct TypeIII : TypeIIIBase, FilterClass
{
void setParams (const Params& params)
{
FilterClass::setup (int(params[1]), params[0], params[2], params[3], params[4]);
}
};

struct TypeIVBase : DesignBase
{
enum
{
NumParams = 6
};

static int getNumParams ()
{
return 6;
}

static const ParamInfo getParamInfo_2 ()
{
return ParamInfo::defaultCenterFrequencyParam ();
}

static const ParamInfo getParamInfo_3 ()
{
return ParamInfo::defaultBandwidthHzParam ();
}

static const ParamInfo getParamInfo_4 ()
{
return ParamInfo::defaultGainParam ();
}

static const ParamInfo getParamInfo_5 ()
{
return ParamInfo::defaultStopDbParam ();
}
};

template <class FilterClass>
struct TypeIV : TypeIVBase, FilterClass
{
void setParams (const Params& params)
{
FilterClass::setup (int(params[1]), params[0], params[2], params[3], params[4], params[5]);
}
};

// Factored kind and name

struct LowPassDescription
{
static Kind getKind () { return kindLowPass; }
static const char* getName() { return "Chebyshev II Low Pass"; }
};

struct HighPassDescription
{
static Kind getKind () { return kindHighPass; }
static const char* getName() { return "Chebyshev II High Pass"; }
};

struct BandPassDescription
{
static Kind getKind () { return kindHighPass; }
static const char* getName() { return "Chebyshev II Band Pass"; }
};

struct BandStopDescription
{
static Kind getKind () { return kindHighPass; }
static const char* getName() { return "Chebyshev II Band Stop"; }
};

struct LowShelfDescription
{
static Kind getKind () { return kindLowShelf; }
static const char* getName() { return "Chebyshev II Low Shelf"; }
};

struct HighShelfDescription
{
static Kind getKind () { return kindHighShelf; }
static const char* getName() { return "Chebyshev II High Shelf"; }
};

struct BandShelfDescription
{
static Kind getKind () { return kindBandShelf; }
static const char* getName() { return "Chebyshev II Band Shelf"; }
};

// This glues on the Order parameter
template <int MaxOrder,
template <class> class TypeClass,
template <int> class FilterClass>
struct OrderBase : TypeClass <FilterClass <MaxOrder> >
{
const ParamInfo getParamInfo_1 () const
{
return ParamInfo (idOrder, "Order", "Order",
1, MaxOrder, 2,
&ParamInfo::Int_toControlValue,
&ParamInfo::Int_toNativeValue,
&ParamInfo::Int_toString);

}
};

//------------------------------------------------------------------------------

//
// Design Filters
//

template <int MaxOrder>
struct LowPass : OrderBase <MaxOrder, TypeI, ChebyshevII::LowPass>,
LowPassDescription
{
};

template <int MaxOrder>
struct HighPass : OrderBase <MaxOrder, TypeI, ChebyshevII::HighPass>,
HighPassDescription
{
};

template <int MaxOrder>
struct BandPass : OrderBase <MaxOrder, TypeII, ChebyshevII::BandPass>,
BandPassDescription
{
};

template <int MaxOrder>
struct BandStop : OrderBase <MaxOrder, TypeII, ChebyshevII::BandStop>,
BandStopDescription
{
};

template <int MaxOrder>
struct LowShelf : OrderBase <MaxOrder, TypeIII, ChebyshevII::LowShelf>,
LowShelfDescription
{
};

template <int MaxOrder>
struct HighShelf : OrderBase <MaxOrder, TypeIII, ChebyshevII::HighShelf>,
HighShelfDescription
{
};

template <int MaxOrder>
struct BandShelf : OrderBase <MaxOrder, TypeIV, ChebyshevII::BandShelf>,
BandShelfDescription
{
};


}

}

}

#endif


+ 66
- 0
ports-juce6/roth-air/DspFilters/Common.h View File

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

"A Collection of Useful C++ Classes for Digital Signal Processing"
By Vincent Falco

Official project location:
http://code.google.com/p/dspfilterscpp/

See Documentation.cpp for contact information, notes, and bibliography.

--------------------------------------------------------------------------------

License: MIT License (http://www.opensource.org/licenses/mit-license.php)
Copyright (c) 2009 by Vincent Falco

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.

*******************************************************************************/

#ifndef DSPFILTERS_COMMON_H
#define DSPFILTERS_COMMON_H

//
// This must be the first file included in every DspFilters header and source
//

#ifdef _MSC_VER
# pragma warning (disable: 4100)
#endif

//#include <assert.h>
#include <stdlib.h>

#include <cassert>
#include <cfloat>
#include <cmath>
#include <complex>
#include <cstring>
#include <string>
#include <limits>
#include <vector>

#ifdef _MSC_VER
namespace tr1 = std::tr1;
#else
namespace tr1 = std;
#endif


#endif

+ 177
- 0
ports-juce6/roth-air/DspFilters/Custom.h View File

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

"A Collection of Useful C++ Classes for Digital Signal Processing"
By Vincent Falco

Official project location:
http://code.google.com/p/dspfilterscpp/

See Documentation.cpp for contact information, notes, and bibliography.

--------------------------------------------------------------------------------

License: MIT License (http://www.opensource.org/licenses/mit-license.php)
Copyright (c) 2009 by Vincent Falco

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.

*******************************************************************************/

#ifndef DSPFILTERS_CUSTOM_H
#define DSPFILTERS_CUSTOM_H

#include "DspFilters/Common.h"
#include "DspFilters/Biquad.h"
#include "DspFilters/Design.h"
#include "DspFilters/Filter.h"

namespace Dsp {

/*
* Single pole and Biquad with parameters allowing
* for directly setting the poles and zeros
*
*/

namespace Custom {

//
// Raw filters
//

struct OnePole : Biquad
{
void setup (double scale,
double pole,
double zero);
};

struct TwoPole : Biquad
{
void setup (double scale,
double poleRho,
double poleTheta,
double zeroRho,
double zeroTheta);
};

//------------------------------------------------------------------------------

//
// Gui-friendly Design layer
//

namespace Design {

struct OnePole : DesignBase, Custom::OnePole
{
enum
{
NumParams = 4
};

static int getNumParams ()
{
return 4;
}

static const ParamInfo getParamInfo_1 ()
{
return ParamInfo::defaultGainParam ();
}

static const ParamInfo getParamInfo_2 ()
{
return ParamInfo::defaultPoleRealParam ();
}

static const ParamInfo getParamInfo_3 ()
{
return ParamInfo::defaultZeroRealParam ();
}

static Kind getKind () { return kindOther; }
static const char* getName() { return "Custom One-Pole"; }

void setParams (const Params& params)
{
setup (pow (10., params[1]/20),
params[2],
params[3]);
}
};

struct TwoPole : DesignBase, Custom::TwoPole
{
enum
{
NumParams = 6
};

static int getNumParams ()
{
return 6;
}

static const ParamInfo getParamInfo_1 ()
{
return ParamInfo::defaultGainParam ();
}

static const ParamInfo getParamInfo_2 ()
{
return ParamInfo::defaultPoleRhoParam ();
}

static const ParamInfo getParamInfo_3 ()
{
return ParamInfo::defaultPoleThetaParam ();
}

static const ParamInfo getParamInfo_4 ()
{
return ParamInfo::defaultZeroRhoParam ();
}

static const ParamInfo getParamInfo_5 ()
{
return ParamInfo::defaultZeroThetaParam ();
}


static Kind getKind () { return kindOther; }
static const char* getName() { return "Custom Two-Pole"; }

void setParams (const Params& params)
{
setup (pow (10., params[1]/20),
params[2],
params[3],
params[4],
params[5]);
}
};

}

}

}

#endif

+ 64
- 0
ports-juce6/roth-air/DspFilters/Design.h View File

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

"A Collection of Useful C++ Classes for Digital Signal Processing"
By Vincent Falco

Official project location:
http://code.google.com/p/dspfilterscpp/

See Documentation.cpp for contact information, notes, and bibliography.

--------------------------------------------------------------------------------

License: MIT License (http://www.opensource.org/licenses/mit-license.php)
Copyright (c) 2009 by Vincent Falco

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.

*******************************************************************************/

#ifndef DSPFILTERS_DESIGN_H
#define DSPFILTERS_DESIGN_H

#include "DspFilters/Common.h"
#include "DspFilters/Params.h"

namespace Dsp {

struct DesignBase
{
// Sampling rate is the first param for every Design filter
static const ParamInfo getParamInfo_0 ()
{
return ParamInfo::defaultSampleRateParam ();
}

// These should never get called
static const ParamInfo getParamInfo_1 () { return ParamInfo(); }
static const ParamInfo getParamInfo_2 () { return ParamInfo(); }
static const ParamInfo getParamInfo_3 () { return ParamInfo(); }
static const ParamInfo getParamInfo_4 () { return ParamInfo(); }
static const ParamInfo getParamInfo_5 () { return ParamInfo(); }
static const ParamInfo getParamInfo_6 () { return ParamInfo(); }
static const ParamInfo getParamInfo_7 () { return ParamInfo(); }
};

}

#endif

+ 62
- 0
ports-juce6/roth-air/DspFilters/Dsp.h View File

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

"A Collection of Useful C++ Classes for Digital Signal Processing"
By Vincent Falco

Official project location:
http://code.google.com/p/dspfilterscpp/

See Documentation.cpp for contact information, notes, and bibliography.

--------------------------------------------------------------------------------

License: MIT License (http://www.opensource.org/licenses/mit-license.php)
Copyright (c) 2009 by Vincent Falco

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.

*******************************************************************************/

#ifndef DSPFILTERS_DSP_H
#define DSPFILTERS_DSP_H

//
// Include this file in your application to get everything
//

#include "DspFilters/Common.h"

#include "DspFilters/Biquad.h"
#include "DspFilters/Cascade.h"
#include "DspFilters/Filter.h"
#include "DspFilters/PoleFilter.h"
#include "DspFilters/SmoothedFilter.h"
#include "DspFilters/State.h"
#include "DspFilters/Utilities.h"

#include "DspFilters/Bessel.h"
#include "DspFilters/Butterworth.h"
#include "DspFilters/ChebyshevI.h"
#include "DspFilters/ChebyshevII.h"
#include "DspFilters/Custom.h"
#include "DspFilters/Elliptic.h"
#include "DspFilters/Legendre.h"
#include "DspFilters/RBJ.h"

#endif

+ 359
- 0
ports-juce6/roth-air/DspFilters/Elliptic.h View File

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

"A Collection of Useful C++ Classes for Digital Signal Processing"
By Vincent Falco

Official project location:
http://code.google.com/p/dspfilterscpp/

See Documentation.cpp for contact information, notes, and bibliography.

--------------------------------------------------------------------------------

License: MIT License (http://www.opensource.org/licenses/mit-license.php)
Copyright (c) 2009 by Vincent Falco

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.

*******************************************************************************/

#ifndef DSPFILTERS_ELLIPTIC_H
#define DSPFILTERS_ELLIPTIC_H

#include "DspFilters/Common.h"
#include "DspFilters/Cascade.h"
#include "DspFilters/Design.h"
#include "DspFilters/Filter.h"
#include "DspFilters/PoleFilter.h"

namespace Dsp {

/*
* Filters with Elliptic response characteristics
*
*/

namespace Elliptic {

// Solves for Jacobi elliptics
class Solver
{
public:
static double ellipticK (double k);
};

// Half-band analog prototype (s-plane)

class AnalogLowPass : public LayoutBase
{
public:
AnalogLowPass ();

void design (const int numPoles,
double rippleDb,
double rolloff);

private:
void prodpoly (int sn);
void calcfz2 (int i);
void calcfz ();
void calcqz ();
double findfact (int t);
double calcsn (double u);

#if 0
template<int n>
struct CalcArray
{
double& operator[](size_t index)
{
assert( index<n );
return m_a[index];
}
private:
double m_a[n];
};
#else
#endif

double m_p0;
double m_q;
double m_K;
double m_Kprime;
double m_e;
int m_nin;
int m_m;
int m_n2;
int m_em;
double m_zeros[100];
double m_c1[100];
double m_b1[100];
double m_a1[100];
double m_d1[100];
double m_q1[100];
double m_z1[100];
double m_f1[100];
double m_s1[100];
double m_p [100];
double m_zw1[100];
double m_zf1[100];
double m_zq1[100];
double m_rootR[100];
double m_rootI[100];

int m_numPoles;
double m_rippleDb;
double m_rolloff;
};

//------------------------------------------------------------------------------

// Factored implementations to reduce template instantiations

struct LowPassBase : PoleFilterBase <AnalogLowPass>
{
void setup (int order,
double sampleRate,
double cutoffFrequency,
double rippleDb,
double rolloff);
};

struct HighPassBase : PoleFilterBase <AnalogLowPass>
{
void setup (int order,
double sampleRate,
double cutoffFrequency,
double rippleDb,
double rolloff);
};

struct BandPassBase : PoleFilterBase <AnalogLowPass>
{
void setup (int order,
double sampleRate,
double centerFrequency,
double widthFrequency,
double rippleDb,
double rolloff);
};

struct BandStopBase : PoleFilterBase <AnalogLowPass>
{
void setup (int order,
double sampleRate,
double centerFrequency,
double widthFrequency,
double rippleDb,
double rolloff);
};

//------------------------------------------------------------------------------

//
// Raw filters
//

template <int MaxOrder>
struct LowPass : PoleFilter <LowPassBase, MaxOrder>
{
};

template <int MaxOrder>
struct HighPass : PoleFilter <HighPassBase, MaxOrder>
{
};

template <int MaxOrder>
struct BandPass : PoleFilter <BandPassBase, MaxOrder, MaxOrder*2>
{
};

template <int MaxOrder>
struct BandStop : PoleFilter <BandStopBase, MaxOrder, MaxOrder*2>
{
};

//------------------------------------------------------------------------------

//
// Gui-friendly Design layer
//

namespace Design {

struct TypeIBase : DesignBase
{
enum
{
NumParams = 5
};

static int getNumParams ()
{
return 5;
}

static const ParamInfo getParamInfo_2 ()
{
return ParamInfo::defaultCutoffFrequencyParam ();
}

static const ParamInfo getParamInfo_3 ()
{
return ParamInfo::defaultRippleDbParam ();
}

static const ParamInfo getParamInfo_4 ()
{
return ParamInfo::defaultRolloffParam ();
}
};

template <class FilterClass>
struct TypeI : TypeIBase, FilterClass
{
void setParams (const Params& params)
{
FilterClass::setup (int(params[1]), params[0], params[2], params[3], params[4]);
}
};

struct TypeIIBase : DesignBase
{
enum
{
NumParams = 6
};

static int getNumParams ()
{
return 6;
}

static const ParamInfo getParamInfo_2 ()
{
return ParamInfo::defaultCenterFrequencyParam ();
}

static const ParamInfo getParamInfo_3 ()
{
return ParamInfo::defaultBandwidthHzParam ();
}

static const ParamInfo getParamInfo_4 ()
{
return ParamInfo::defaultRippleDbParam ();
}

static const ParamInfo getParamInfo_5 ()
{
return ParamInfo::defaultRolloffParam ();
}
};

template <class FilterClass>
struct TypeII : TypeIIBase, FilterClass
{
void setParams (const Params& params)
{
FilterClass::setup (int(params[1]), params[0], params[2], params[3], params[4], params[5]);
}
};

// Factored kind and name

struct LowPassDescription
{
static Kind getKind () { return kindLowPass; }
static const char* getName() { return "Elliptic Low Pass"; }
};

struct HighPassDescription
{
static Kind getKind () { return kindHighPass; }
static const char* getName() { return "Elliptic High Pass"; }
};

struct BandPassDescription
{
static Kind getKind () { return kindHighPass; }
static const char* getName() { return "Elliptic Band Pass"; }
};

struct BandStopDescription
{
static Kind getKind () { return kindHighPass; }
static const char* getName() { return "Elliptic Band Stop"; }
};

// This glues on the Order parameter
template <int MaxOrder,
template <class> class TypeClass,
template <int> class FilterClass>
struct OrderBase : TypeClass <FilterClass <MaxOrder> >
{
const ParamInfo getParamInfo_1 () const
{
return ParamInfo (idOrder, "Order", "Order",
1, MaxOrder, 2,
&ParamInfo::Int_toControlValue,
&ParamInfo::Int_toNativeValue,
&ParamInfo::Int_toString);

}
};
//------------------------------------------------------------------------------

//
// Design filters
//

template <int MaxOrder>
struct LowPass : OrderBase <MaxOrder, TypeI, Elliptic::LowPass>,
LowPassDescription
{
};

template <int MaxOrder>
struct HighPass : OrderBase <MaxOrder, TypeI, Elliptic::HighPass>,
HighPassDescription
{
};

template <int MaxOrder>
struct BandPass : OrderBase <MaxOrder, TypeII, Elliptic::BandPass>,
BandPassDescription
{
};

template <int MaxOrder>
struct BandStop : OrderBase <MaxOrder, TypeII, Elliptic::BandStop>,
BandStopDescription
{
};

}

}

}

#endif


+ 269
- 0
ports-juce6/roth-air/DspFilters/Filter.h View File

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

"A Collection of Useful C++ Classes for Digital Signal Processing"
By Vincent Falco

Official project location:
http://code.google.com/p/dspfilterscpp/

See Documentation.cpp for contact information, notes, and bibliography.

--------------------------------------------------------------------------------

License: MIT License (http://www.opensource.org/licenses/mit-license.php)
Copyright (c) 2009 by Vincent Falco

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.

*******************************************************************************/

#ifndef DSPFILTERS_FILTER_H
#define DSPFILTERS_FILTER_H

#include "DspFilters/Common.h"
#include "DspFilters/MathSupplement.h"
#include "DspFilters/Params.h"
#include "DspFilters/State.h"
#include "DspFilters/Types.h"

namespace Dsp {

/*
* Filter
*
* Full abstraction of a digital IIR filter.
* Supports run-time introspection and modulation of filter
* parameters.
*
*/
class Filter
{
public:
virtual ~Filter();

virtual Kind getKind () const = 0;

virtual const std::string getName () const = 0;

virtual int getNumParams () const = 0;

virtual ParamInfo getParamInfo (int index) const = 0;

Params getDefaultParams() const;

const Params& getParams() const
{
return m_params;
}

double getParam (int paramIndex) const
{
assert (paramIndex >= 0 && paramIndex <= getNumParams());
return m_params[paramIndex];
}

void setParam (int paramIndex, double nativeValue)
{
assert (paramIndex >= 0 && paramIndex <= getNumParams());
m_params[paramIndex] = nativeValue;
doSetParams (m_params);
}

int findParamId (int paramId);

void setParamById (int paramId, double nativeValue);

void setParams (const Params& parameters)
{
m_params = parameters;
doSetParams (parameters);
}

// This makes a best-effort to pick up the values
// of matching parameters from another set. It uses
// the ParamID information to make the match.
void copyParamsFrom (Dsp::Filter const* other);

virtual std::vector<PoleZeroPair> getPoleZeros() const = 0;
virtual complex_t response (double normalizedFrequency) const = 0;

virtual int getNumChannels() = 0;
virtual void reset () = 0;
virtual void process (int numSamples, float* const* arrayOfChannels) = 0;
virtual void process (int numSamples, double* const* arrayOfChannels) = 0;

protected:
virtual void doSetParams (const Params& parameters) = 0;

private:
Params m_params;
};

//------------------------------------------------------------------------------

/*
* FilterDesign
*
* This container holds a filter Design (Gui-friendly layer) and
* optionally combines it with the necessary state information to
* process channel data.
*
*/

// Factored to reduce template instantiations
template <class DesignClass>
class FilterDesignBase : public Filter
{
public:
Kind getKind () const
{
return m_design.getKind ();
}

const std::string getName () const
{
return m_design.getName ();
}

int getNumParams () const
{
return DesignClass::NumParams;
}

Params getDefaultParams() const
{
return m_design.getDefaultParams();
}

ParamInfo getParamInfo (int index) const
{
switch (index)
{
case 0: return m_design.getParamInfo_0 ();
case 1: return m_design.getParamInfo_1 ();
case 2: return m_design.getParamInfo_2 ();
case 3: return m_design.getParamInfo_3 ();
case 4: return m_design.getParamInfo_4 ();
case 5: return m_design.getParamInfo_5 ();
case 6: return m_design.getParamInfo_6 ();
case 7: return m_design.getParamInfo_7 ();
};

return ParamInfo();
}

std::vector<PoleZeroPair> getPoleZeros() const
{
return m_design.getPoleZeros();
}
complex_t response (double normalizedFrequency) const
{
return m_design.response (normalizedFrequency);
}

protected:
void doSetParams (const Params& parameters)
{
m_design.setParams (parameters);
}

protected:
DesignClass m_design;
};



template <class DesignClass,
int Channels = 0,
class StateType = DirectFormII>
class FilterDesign : public FilterDesignBase <DesignClass>
{
public:
FilterDesign ()
{
}

int getNumChannels()
{
return Channels;
}

void reset ()
{
m_state.reset();
}

void process (int numSamples, float* const* arrayOfChannels)
{
m_state.process (numSamples, arrayOfChannels,
FilterDesignBase<DesignClass>::m_design);
}

void process (int numSamples, double* const* arrayOfChannels)
{
m_state.process (numSamples, arrayOfChannels,
FilterDesignBase<DesignClass>::m_design);
}

protected:
ChannelsState <Channels,
typename DesignClass::template State <StateType> > m_state;
};

//------------------------------------------------------------------------------

/*
* This container combines a raw filter with state information
* so it can process channels. In order to set up the filter you
* must call a setup function directly. Smooth changes are
* not supported, but this class has a smaller footprint.
*
*/
template <class FilterClass,
int Channels = 0,
class StateType = DirectFormII>
class SimpleFilter : public FilterClass
{
public:
int getNumChannels()
{
return Channels;
}

void reset ()
{
m_state.reset();
}

template <typename Sample>
void process (int numSamples, Sample* const* arrayOfChannels)
{
m_state.process (numSamples, arrayOfChannels, *((FilterClass*)this));
}

protected:
ChannelsState <Channels,
typename FilterClass::template State <StateType> > m_state;
};

}

#endif

+ 170
- 0
ports-juce6/roth-air/DspFilters/Layout.h View File

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

"A Collection of Useful C++ Classes for Digital Signal Processing"
By Vincent Falco

Official project location:
http://code.google.com/p/dspfilterscpp/

See Documentation.cpp for contact information, notes, and bibliography.

--------------------------------------------------------------------------------

License: MIT License (http://www.opensource.org/licenses/mit-license.php)
Copyright (c) 2009 by Vincent Falco

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.

*******************************************************************************/

#ifndef DSPFILTERS_LAYOUT_H
#define DSPFILTERS_LAYOUT_H

#include "DspFilters/Common.h"
#include "DspFilters/MathSupplement.h"

namespace Dsp {

//
// Describes a filter as a collection of poles and zeros along with
// normalization information to achieve a specified gain at a specified
// frequency. The poles and zeros may lie either in the s or the z plane.
//

// Base uses pointers to reduce template instantiations
class LayoutBase
{
public:
LayoutBase ()
: m_numPoles (0)
, m_maxPoles (0)
{
}

LayoutBase (int maxPoles, PoleZeroPair* pairs)
: m_numPoles (0)
, m_maxPoles (maxPoles)
, m_pair (pairs)
{
}

void setStorage (const LayoutBase& other)
{
m_numPoles = 0;
m_maxPoles = other.m_maxPoles;
m_pair = other.m_pair;
}

void reset ()
{
m_numPoles = 0;
}

int getNumPoles () const
{
return m_numPoles;
}

int getMaxPoles () const
{
return m_maxPoles;
}

void add (const complex_t& pole, const complex_t& zero)
{
assert (!(m_numPoles&1)); // single comes last
assert (!Dsp::is_nan (pole));
m_pair[m_numPoles/2] = PoleZeroPair (pole, zero);
++m_numPoles;
}

void addPoleZeroConjugatePairs (const complex_t pole,
const complex_t zero)
{
assert (!(m_numPoles&1)); // single comes last
assert (!Dsp::is_nan (pole));
m_pair[m_numPoles/2] = PoleZeroPair (
pole, zero, std::conj (pole), std::conj (zero));
m_numPoles += 2;
}

void add (const ComplexPair& poles, const ComplexPair& zeros)
{
assert (!(m_numPoles&1)); // single comes last
assert (poles.isMatchedPair ());
assert (zeros.isMatchedPair ());
m_pair[m_numPoles/2] = PoleZeroPair (poles.first, zeros.first,
poles.second, zeros.second);
m_numPoles += 2;
}

const PoleZeroPair& getPair (int pairIndex) const
{
assert (pairIndex >= 0 && pairIndex < (m_numPoles+1)/2);
return m_pair[pairIndex];
}

const PoleZeroPair& operator[] (int pairIndex) const
{
return getPair (pairIndex);
}

double getNormalW () const
{
return m_normalW;
}

double getNormalGain () const
{
return m_normalGain;
}

void setNormal (double w, double g)
{
m_normalW = w;
m_normalGain = g;
}

private:
int m_numPoles;
int m_maxPoles;
PoleZeroPair* m_pair;
double m_normalW;
double m_normalGain;
};

//------------------------------------------------------------------------------

// Storage for Layout
template <int MaxPoles>
class Layout
{
public:
operator LayoutBase ()
{
return LayoutBase (MaxPoles, m_pairs);
}

private:
PoleZeroPair m_pairs[(MaxPoles+1)/2];
};

}

#endif

+ 417
- 0
ports-juce6/roth-air/DspFilters/Legendre.h View File

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

"A Collection of Useful C++ Classes for Digital Signal Processing"
By Vincent Falco

Official project location:
http://code.google.com/p/dspfilterscpp/

See Documentation.cpp for contact information, notes, and bibliography.

--------------------------------------------------------------------------------

License: MIT License (http://www.opensource.org/licenses/mit-license.php)
Copyright (c) 2009 by Vincent Falco

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.

*******************************************************************************/

#ifndef DSPFILTERS_LEGENDRE_H
#define DSPFILTERS_LEGENDRE_H

#include "DspFilters/Common.h"
#include "DspFilters/Cascade.h"
#include "DspFilters/Design.h"
#include "DspFilters/Filter.h"
#include "DspFilters/PoleFilter.h"
#include "DspFilters/RootFinder.h"

namespace Dsp {

/*
* Filters with Legendre / "Optimum-L" response characteristics
*
*/

namespace Legendre {

// Numerical computation of Legendre "Optimum-L" polynomials

class PolynomialFinderBase
{
public:
void solve (int n);

double* coef()
{
return m_w;
}

private:
void legendre (double* p, int n);

protected:
int m_maxN;
double* m_w;
double* m_a;
double* m_p;
double* m_s;
double* m_v;
double* m_aa;
double* m_bb;
};

template <int maxN>
class PolynomialFinder : public PolynomialFinderBase
{
public:
PolynomialFinder ()
{
m_maxN = maxN;
m_w = m_ws;
m_a = m_as;
m_p = m_ps;
m_s = m_ss;
m_v = m_vs;
m_aa = m_aas;
m_bb = m_bbs;
}

void solve (int n)
{
assert (n <= maxN);
PolynomialFinderBase::solve (n);
}

private:
double m_ws [2 * maxN + 1];
double m_as [ maxN + 1];
double m_ps [2 * maxN + 1];
double m_ss [2 * maxN + 1];
double m_vs [2 * maxN + 4];
double m_aas [ maxN + 1];
double m_bbs [ maxN + 1];
};

//------------------------------------------------------------------------------

// A Workspace is necessary to construct the polynomial and find its roots

struct WorkspaceBase
{
WorkspaceBase (PolynomialFinderBase* polyBase,
RootFinderBase* rootsBase)
: poly (*polyBase)
, roots (*rootsBase)
{
}

PolynomialFinderBase& poly;
RootFinderBase& roots;

private:
WorkspaceBase (WorkspaceBase&);
WorkspaceBase& operator= (WorkspaceBase&);
};

template <int MaxOrder>
struct Workspace : WorkspaceBase
{
Workspace ()
: WorkspaceBase (&m_poly, &m_roots)
{
}

private:
PolynomialFinder <MaxOrder> m_poly;
RootFinder <MaxOrder * 2> m_roots;
};

//------------------------------------------------------------------------------

// Half-band analog prototypes (s-plane)

class AnalogLowPass : public LayoutBase
{
public:
AnalogLowPass ();

void design (const int numPoles, WorkspaceBase* w);

private:
int m_numPoles;
};

//------------------------------------------------------------------------------

// Factored implementations to reduce template instantiations

struct LowPassBase : PoleFilterBase <AnalogLowPass>
{
void setup (int order,
double sampleRate,
double cutoffFrequency,
WorkspaceBase* w);
};

struct HighPassBase : PoleFilterBase <AnalogLowPass>
{
void setup (int order,
double sampleRate,
double cutoffFrequency,
WorkspaceBase* w);
};

struct BandPassBase : PoleFilterBase <AnalogLowPass>
{
void setup (int order,
double sampleRate,
double centerFrequency,
double widthFrequency,
WorkspaceBase* w);
};

struct BandStopBase : PoleFilterBase <AnalogLowPass>
{
void setup (int order,
double sampleRate,
double centerFrequency,
double widthFrequency,
WorkspaceBase* w);
};

//------------------------------------------------------------------------------

//
// Raw filters
//

template <int MaxOrder>
struct LowPass : PoleFilter <LowPassBase, MaxOrder>
{
void setup (int order,
double sampleRate,
double cutoffFrequency)
{
Workspace <MaxOrder> w;
LowPassBase::setup (order,
sampleRate,
cutoffFrequency,
&w);
}
};

template <int MaxOrder>
struct HighPass : PoleFilter <HighPassBase, MaxOrder>
{
void setup (int order,
double sampleRate,
double cutoffFrequency)
{
Workspace <MaxOrder> w;
HighPassBase::setup (order,
sampleRate,
cutoffFrequency,
&w);
}
};

template <int MaxOrder>
struct BandPass : PoleFilter <BandPassBase, MaxOrder, MaxOrder*2>
{
void setup (int order,
double sampleRate,
double centerFrequency,
double widthFrequency)
{
Workspace <MaxOrder> w;
BandPassBase::setup (order,
sampleRate,
centerFrequency,
widthFrequency,
&w);
}
};

template <int MaxOrder>
struct BandStop : PoleFilter <BandStopBase, MaxOrder, MaxOrder*2>
{
void setup (int order,
double sampleRate,
double centerFrequency,
double widthFrequency)
{
Workspace <MaxOrder> w;
BandStopBase::setup (order,
sampleRate,
centerFrequency,
widthFrequency,
&w);
}
};

//------------------------------------------------------------------------------

//
// Gui-friendly Design layer
//

namespace Design {

struct TypeIBase : DesignBase
{
enum
{
NumParams = 3
};

static int getNumParams ()
{
return 3;
}

static const ParamInfo getParamInfo_2 ()
{
return ParamInfo::defaultCutoffFrequencyParam ();
}
};

template <class FilterClass>
struct TypeI : TypeIBase, FilterClass
{
void setParams (const Params& params)
{
FilterClass::setup (int(params[1]), params[0], params[2]);
}
};

struct TypeIIBase : DesignBase
{
enum
{
NumParams = 4
};

static int getNumParams ()
{
return 4;
}

static const ParamInfo getParamInfo_2 ()
{
return ParamInfo::defaultCenterFrequencyParam ();
}

static const ParamInfo getParamInfo_3 ()
{
return ParamInfo::defaultBandwidthHzParam ();
}
};

template <class FilterClass>
struct TypeII : TypeIIBase, FilterClass
{
void setParams (const Params& params)
{
FilterClass::setup (int(params[1]), params[0], params[2], params[3]);
}
};

// Factored kind and name

struct LowPassDescription
{
static Kind getKind () { return kindLowPass; }
static const char* getName() { return "Legendre Low Pass"; }
};

struct HighPassDescription
{
static Kind getKind () { return kindHighPass; }
static const char* getName() { return "Legendre High Pass"; }
};

struct BandPassDescription
{
static Kind getKind () { return kindHighPass; }
static const char* getName() { return "Legendre Band Pass"; }
};

struct BandStopDescription
{
static Kind getKind () { return kindHighPass; }
static const char* getName() { return "Legendre Band Stop"; }
};

// This glues on the Order parameter
template <int MaxOrder,
template <class> class TypeClass,
template <int> class FilterClass>
struct OrderBase : TypeClass <FilterClass <MaxOrder> >
{
const ParamInfo getParamInfo_1 () const
{
return ParamInfo (idOrder, "Order", "Order",
1, MaxOrder, 2,
&ParamInfo::Int_toControlValue,
&ParamInfo::Int_toNativeValue,
&ParamInfo::Int_toString);

}
};

//------------------------------------------------------------------------------

//
// Design filters
//

template <int MaxOrder>
struct LowPass : OrderBase <MaxOrder, TypeI, Legendre::LowPass>,
LowPassDescription
{
};

template <int MaxOrder>
struct HighPass : OrderBase <MaxOrder, TypeI, Legendre::HighPass>,
HighPassDescription
{
};

template <int MaxOrder>
struct BandPass : OrderBase <MaxOrder, TypeII, Legendre::BandPass>,
BandPassDescription
{
};

template <int MaxOrder>
struct BandStop : OrderBase <MaxOrder, TypeII, Legendre::BandStop>,
BandStopDescription
{
};

}

}

}

#endif


+ 154
- 0
ports-juce6/roth-air/DspFilters/MathSupplement.h View File

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

"A Collection of Useful C++ Classes for Digital Signal Processing"
By Vincent Falco

Official project location:
http://code.google.com/p/dspfilterscpp/

See Documentation.cpp for contact information, notes, and bibliography.

--------------------------------------------------------------------------------

License: MIT License (http://www.opensource.org/licenses/mit-license.php)
Copyright (c) 2009 by Vincent Falco

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.

*******************************************************************************/

#ifndef DSPFILTERS_MATHSUPPLEMENT_H
#define DSPFILTERS_MATHSUPPLEMENT_H

#include "DspFilters/Common.h"

namespace Dsp {

const double doublePi =3.1415926535897932384626433832795028841971;
const double doublePi_2 =1.5707963267948966192313216916397514420986;
const double doubleLn2 =0.69314718055994530941723212145818;//?????
const double doubleLn10 =2.3025850929940456840179914546844;//??????

typedef std::complex<double> complex_t;
typedef std::pair<complex_t, complex_t> complex_pair_t;

template<typename Real>
inline std::complex<Real> solve_quadratic_1 (Real a, Real b, Real c)
{
return (-b + sqrt (std::complex<Real> (b*b - 4*a*c, 0))) / (2. * a);
}

template<typename Real>
inline std::complex<Real> solve_quadratic_2 (Real a, Real b, Real c)
{
return (-b - sqrt (std::complex<Real> (b*b - 4*a*c, 0))) / (2. * a);
}

inline const complex_t infinity()
{
return complex_t (std::numeric_limits<double>::infinity());
}

inline const complex_t adjust_imag (const complex_t& c)
{
if (fabs (c.imag()) < 1e-30)
return complex_t (c.real(), 0);
else
return c;
}

template <typename Ty, typename To>
inline std::complex<Ty> addmul (const std::complex<Ty>& c,
Ty v,
const std::complex<To>& c1)
{
return std::complex <Ty> (
c.real() + v * c1.real(), c.imag() + v * c1.imag());
}

template <typename Ty>
inline std::complex<Ty> recip (const std::complex<Ty>& c)
{
Ty n = 1.0 / std::norm (c);
return std::complex<Ty> (n * c.real(), n * c.imag());
}

template <typename Ty>
inline Ty asinh (Ty x)
{
return log (x + std::sqrt (x * x + 1 ));
}

template <typename Ty>
inline Ty acosh (Ty x)
{
return log (x + std::sqrt (x * x - 1));
}

template <typename Ty>
inline bool is_nan (Ty v)
{
return !(v == v);
}

template <>
inline bool is_nan<complex_t> (complex_t v)
{
return Dsp::is_nan (v.real()) || Dsp::is_nan (v.imag());
}

//------------------------------------------------------------------------------

/*
* Hack to prevent denormals
*
*/

//const double anti_denormal_vsa = 1e-16; // doesn't prevent denormals
//const double anti_denormal_vsa = 0;
const double anti_denormal_vsa = 1e-8;

class DenormalPrevention
{
public:
DenormalPrevention ()
: m_v (anti_denormal_vsa)
{
}

// small alternating current
inline double ac ()
{
return m_v = -m_v;
}

// small direct current
static inline double dc ()
{
return anti_denormal_vsa;
}

private:
double m_v;
};

}

#endif

+ 244
- 0
ports-juce6/roth-air/DspFilters/Params.h View File

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

"A Collection of Useful C++ Classes for Digital Signal Processing"
By Vincent Falco

Official project location:
http://code.google.com/p/dspfilterscpp/

See Documentation.cpp for contact information, notes, and bibliography.

--------------------------------------------------------------------------------

License: MIT License (http://www.opensource.org/licenses/mit-license.php)
Copyright (c) 2009 by Vincent Falco

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.

*******************************************************************************/

#ifndef DSPFILTERS_PARAMS_H
#define DSPFILTERS_PARAMS_H

#include "DspFilters/Common.h"
#include "DspFilters/Types.h"

namespace Dsp {

/*
* System for abstracting parameterizable filter specifications.
*
* This provides a "GUI-friendly" layer to the filters. Note that
* it is not necessary to use this layer, it is possible to instantiate
* the filters and their associated processing state directly,
* and bypass the overhead for this API if it is not needed.
*
*/

// Unique IDs to help identify parameters
enum ParamID
{
idSampleRate,
idFrequency,
idQ,
idBandwidth,
idBandwidthHz,
idGain,
idSlope,
idOrder,
idRippleDb,
idStopDb,
idRolloff,

idPoleRho,
idPoleTheta,
idZeroRho,
idZeroTheta,

idPoleReal,
idZeroReal
};

enum
{
maxParameters = 8
};

struct Params
{
void clear ()
{
for (int i = 0; i < maxParameters; ++i)
value[i] = 0;
}

double& operator[] (int index)
{
return value[index];
}

const double& operator[] (int index) const
{
return value[index];
}

double value[maxParameters];
};

//
// Provides meta-information about a filter parameter
// to achieve run-time introspection.
//
class ParamInfo
{
public:
typedef double (ParamInfo::*toControlValue_t) (double) const;
typedef double (ParamInfo::*toNativeValue_t) (double) const;
typedef std::string (ParamInfo::*toString_t) (double) const;

// dont use this one
ParamInfo (); // throws std::logic_error

ParamInfo (ParamID id,
const char* szLabel,
const char* szName,
double arg1,
double arg2,
double defaultNativeValue,
toControlValue_t toControlValue_proc,
toNativeValue_t toNativeValue_proc,
toString_t toString_proc)
: m_id (id)
, m_szLabel (szLabel)
, m_szName (szName)
, m_arg1 (arg1)
, m_arg2 (arg2)
, m_defaultNativeValue (defaultNativeValue)
, m_toControlValue (toControlValue_proc)
, m_toNativeValue (toNativeValue_proc)
, m_toString (toString_proc)
{
}

// Used to identify well-known parameters (like cutoff frequency)
ParamID getId () const
{
return m_id;
}

// Returns a short label suitable for placement on a control
const char* getLabel () const
{
return m_szLabel;
}

// Returns the full name
const char* getName () const
{
return m_szName;
}

double getDefaultValue () const
{
return m_defaultNativeValue;
}

//
// Control value is always in the range [0..1]
//
double toControlValue (double nativeValue) const
{
return (this->*m_toControlValue) (nativeValue);
}

//
// Native value is in filter-specific units. For example,
// cutoff frequency would probably be in Hertz.
//
double toNativeValue (double controlValue) const
{
return (this->*m_toNativeValue) (controlValue);
}

std::string toString (double nativeValue) const
{
return (this->*m_toString) (nativeValue);
}

double clamp (double nativeValue) const;

//
// These routines are used as function pointers when
// constructing the various ParamInfo used by filters
//

double Int_toControlValue (double nativeValue) const;
double Int_toNativeValue (double controlValue) const;

double Real_toControlValue (double nativeValue) const;
double Real_toNativeValue (double controlValue) const;

double Log_toControlValue (double nativeValue) const;
double Log_toNativeValue (double controlValue) const;

double Pow2_toControlValue (double nativeValue) const;
double Pow2_toNativeValue (double controlValue) const;

std::string Int_toString (double nativeValue) const;
std::string Hz_toString (double nativeValue) const;
std::string Real_toString (double nativeValue) const;
std::string Db_toString (double nativeValue) const;

//
// Creates the specified ParamInfo
//

static ParamInfo defaultSampleRateParam ();
static ParamInfo defaultCutoffFrequencyParam ();
static ParamInfo defaultCenterFrequencyParam ();
static ParamInfo defaultQParam ();
static ParamInfo defaultBandwidthParam ();
static ParamInfo defaultBandwidthHzParam ();
static ParamInfo defaultGainParam ();
static ParamInfo defaultSlopeParam ();
static ParamInfo defaultRippleDbParam ();
static ParamInfo defaultStopDbParam ();
static ParamInfo defaultRolloffParam ();
static ParamInfo defaultPoleRhoParam ();
static ParamInfo defaultPoleThetaParam ();
static ParamInfo defaultZeroRhoParam ();
static ParamInfo defaultZeroThetaParam ();
static ParamInfo defaultPoleRealParam ();
static ParamInfo defaultZeroRealParam ();

private:
ParamID m_id;
const char* m_szLabel;
const char* m_szName;
double m_arg1;
double m_arg2;
double m_defaultNativeValue;
toControlValue_t m_toControlValue;
toNativeValue_t m_toNativeValue;
toString_t m_toString;
};

}

#endif

+ 217
- 0
ports-juce6/roth-air/DspFilters/PoleFilter.h View File

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

"A Collection of Useful C++ Classes for Digital Signal Processing"
By Vincent Falco

Official project location:
http://code.google.com/p/dspfilterscpp/

See Documentation.cpp for contact information, notes, and bibliography.

--------------------------------------------------------------------------------

License: MIT License (http://www.opensource.org/licenses/mit-license.php)
Copyright (c) 2009 by Vincent Falco

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.

*******************************************************************************/

#ifndef DSPFILTERS_POLEFILTER_H
#define DSPFILTERS_POLEFILTER_H

#include "DspFilters/Common.h"
#include "DspFilters/MathSupplement.h"
#include "DspFilters/Cascade.h"

namespace Dsp {

/*
* Base for filters designed via algorithmic placement of poles and zeros.
*
* Typically, the filter is first designed as a half-band low pass or
* low shelf analog filter (s-plane). Then, using a transformation such
* as the ones from Constantinides, the poles and zeros of the analog filter
* are calculated in the z-plane.
*
*/

// Factored implementations to reduce template instantiations

class PoleFilterBase2 : public Cascade
{
public:
// This gets the poles/zeros directly from the digital
// prototype. It is used to double check the correctness
// of the recovery of pole/zeros from biquad coefficients.
//
// It can also be used to accelerate the interpolation
// of pole/zeros for parameter modulation, since a pole
// filter already has them calculated

#if 1
// Commenting this out will pass the call to the Cascade,
// which tries to compute the poles and zeros from the biquad
// coefficients.
std::vector<PoleZeroPair> getPoleZeros () const
{
std::vector<PoleZeroPair> vpz;
const int pairs = (m_digitalProto.getNumPoles () + 1) / 2;
for (int i = 0; i < pairs; ++i)
vpz.push_back (m_digitalProto[i]);
return vpz;
}
#endif

protected:
LayoutBase m_digitalProto;
};

// Serves a container to hold the analog prototype
// and the digital pole/zero layout.
template <class AnalogPrototype>
class PoleFilterBase : public PoleFilterBase2
{
protected:
void setPrototypeStorage (const LayoutBase& analogStorage,
const LayoutBase& digitalStorage)
{
m_analogProto.setStorage (analogStorage);
m_digitalProto = digitalStorage;
}

protected:
AnalogPrototype m_analogProto;
};

//------------------------------------------------------------------------------

// Storage for pole filters
template <class BaseClass,
int MaxAnalogPoles,
int MaxDigitalPoles = MaxAnalogPoles>
struct PoleFilter : BaseClass
, CascadeStages <(MaxDigitalPoles + 1) / 2>
{
PoleFilter ()
{
// This glues together the factored base classes
// with the templatized storage classes.
BaseClass::setCascadeStorage (this->getCascadeStorage());
BaseClass::setPrototypeStorage (m_analogStorage, m_digitalStorage);
}

private:
Layout <MaxAnalogPoles> m_analogStorage;
Layout <MaxDigitalPoles> m_digitalStorage;
};

//------------------------------------------------------------------------------

/*
* s-plane to z-plane transforms
*
* For pole filters, an analog prototype is created via placement of
* poles and zeros in the s-plane. The analog prototype is either
* a halfband low pass or a halfband low shelf. The poles, zeros,
* and normalization parameters are transformed into the z-plane
* using variants of the bilinear transformation.
*
*/

// low pass to low pass
class LowPassTransform
{
public:
LowPassTransform (double fc,
LayoutBase& digital,
LayoutBase const& analog);

private:
complex_t transform (complex_t c);

double f;
};

//------------------------------------------------------------------------------

// low pass to high pass
class HighPassTransform
{
public:
HighPassTransform (double fc,
LayoutBase& digital,
LayoutBase const& analog);

private:
complex_t transform (complex_t c);

double f;
};

//------------------------------------------------------------------------------

// low pass to band pass transform
class BandPassTransform
{

public:
BandPassTransform (double fc,
double fw,
LayoutBase& digital,
LayoutBase const& analog);

private:
ComplexPair transform (complex_t c);

double wc;
double wc2;
double a;
double b;
double a2;
double b2;
double ab;
double ab_2;
};

//------------------------------------------------------------------------------

// low pass to band stop transform
class BandStopTransform
{
public:
BandStopTransform (double fc,
double fw,
LayoutBase& digital,
LayoutBase const& analog);

private:
ComplexPair transform (complex_t c);

double wc;
double wc2;
double a;
double b;
double a2;
double b2;
};

}

#endif

+ 335
- 0
ports-juce6/roth-air/DspFilters/RBJ.h View File

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

"A Collection of Useful C++ Classes for Digital Signal Processing"
By Vincent Falco

Official project location:
http://code.google.com/p/dspfilterscpp/

See Documentation.cpp for contact information, notes, and bibliography.

--------------------------------------------------------------------------------

License: MIT License (http://www.opensource.org/licenses/mit-license.php)
Copyright (c) 2009 by Vincent Falco

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.

*******************************************************************************/

#ifndef DSPFILTERS_RBJ_H
#define DSPFILTERS_RBJ_H

#include "DspFilters/Common.h"
#include "DspFilters/Biquad.h"
#include "DspFilters/Design.h"
#include "DspFilters/Filter.h"

namespace Dsp {

/*
* Filter realizations based on Robert Bristol-Johnson formulae:
*
* http://www.musicdsp.org/files/Audio-EQ-Cookbook.txt
*
*/

namespace RBJ {

//
// Raw filters
//

struct LowPass : BiquadBase
{
void setup (double sampleRate,
double cutoffFrequency,
double q);
};

struct HighPass : BiquadBase
{
void setup (double sampleRate,
double cutoffFrequency,
double q);
};

struct BandPass1 : BiquadBase
{
// (constant skirt gain, peak gain = Q)
void setup (double sampleRate,
double centerFrequency,
double bandWidth);
};

struct BandPass2 : BiquadBase
{
// (constant 0 dB peak gain)
void setup (double sampleRate,
double centerFrequency,
double bandWidth);
};

struct BandStop : BiquadBase
{
void setup (double sampleRate,
double centerFrequency,
double bandWidth);
};

struct LowShelf : BiquadBase
{
void setup (double sampleRate,
double cutoffFrequency,
double gainDb,
double shelfSlope);
};

struct HighShelf : BiquadBase
{
void setup (double sampleRate,
double cutoffFrequency,
double gainDb,
double shelfSlope);
};

struct BandShelf : BiquadBase
{
void setup (double sampleRate,
double centerFrequency,
double gainDb,
double bandWidth);
};

struct AllPass : BiquadBase
{
void setup (double sampleRate,
double phaseFrequency,
double q);
};

//------------------------------------------------------------------------------

//
// Gui-friendly Design layer
//

namespace Design {

struct TypeIBase : DesignBase
{
enum
{
NumParams = 3
};

static int getNumParams ()
{
return 3;
}

static const ParamInfo getParamInfo_1 ()
{
return ParamInfo::defaultCutoffFrequencyParam ();
}

static const ParamInfo getParamInfo_2 ()
{
return ParamInfo::defaultQParam ();
}
};

template <class FilterClass>
struct TypeI : TypeIBase, FilterClass
{
void setParams (const Params& params)
{
FilterClass::setup (params[0], params[1], params[2]);
}
};

struct TypeIIBase : DesignBase
{
enum
{
NumParams = 3
};

static int getNumParams ()
{
return 3;
}

static const ParamInfo getParamInfo_1 ()
{
return ParamInfo::defaultCenterFrequencyParam ();
}

static const ParamInfo getParamInfo_2 ()
{
return ParamInfo::defaultBandwidthParam ();
}
};

template <class FilterClass>
struct TypeII : TypeIIBase, FilterClass
{
void setParams (const Params& params)
{
FilterClass::setup (params[0], params[1], params[2]);
}
};

struct TypeIIIBase : DesignBase
{
enum
{
NumParams = 4
};

static int getNumParams ()
{
return 4;
}

static const ParamInfo getParamInfo_1 ()
{
return ParamInfo::defaultCutoffFrequencyParam ();
}

static const ParamInfo getParamInfo_2 ()
{
return ParamInfo::defaultGainParam ();
}

static const ParamInfo getParamInfo_3 ()
{
return ParamInfo::defaultSlopeParam ();
}
};

template <class FilterClass>
struct TypeIII : TypeIIIBase, FilterClass
{
void setParams (const Params& params)
{
FilterClass::setup (params[0], params[1], params[2], params[3]);
}
};

struct TypeIVBase : DesignBase
{
enum
{
NumParams = 4
};

static int getNumParams ()
{
return 4;
}

static const ParamInfo getParamInfo_1 ()
{
return ParamInfo::defaultCenterFrequencyParam ();
}

static const ParamInfo getParamInfo_2 ()
{
return ParamInfo::defaultGainParam ();
}

static const ParamInfo getParamInfo_3 ()
{
return ParamInfo::defaultBandwidthParam ();
}
};

template <class FilterClass>
struct TypeIV : TypeIVBase , FilterClass
{
void setParams (const Params& params)
{
FilterClass::setup (params[0], params[1], params[2], params[3]);
}
};

//------------------------------------------------------------------------------

struct LowPass : TypeI <RBJ::LowPass>
{
static Kind getKind () { return kindLowPass; }
static const char* getName() { return "RBJ Low Pass"; }
};

struct HighPass : TypeI <RBJ::HighPass>
{
static Kind getKind () { return kindHighPass; }
static const char* getName() { return "RBJ High Pass"; }
};

struct BandPass1 : TypeII <RBJ::BandPass1>
{
static Kind getKind () { return kindBandPass; }
static const char* getName() { return "RBJ Band Pass 1"; }
};

struct BandPass2 : TypeII <RBJ::BandPass2>
{
static Kind getKind () { return kindBandPass; }
static const char* getName() { return "RBJ Band Pass 2"; }
};

struct BandStop : TypeII <RBJ::BandStop>
{
static Kind getKind () { return kindBandStop; }
static const char* getName() { return "RBJ Band Stop"; }
};

struct LowShelf : TypeIII <RBJ::LowShelf>
{
static Kind getKind () { return kindLowShelf; }
static const char* getName() { return "RBJ Low Shelf"; }
};

struct HighShelf : TypeIII <RBJ::HighShelf>
{
static Kind getKind () { return kindHighShelf; }
static const char* getName() { return "RBJ High Shelf"; }
};

struct BandShelf : TypeIV <RBJ::BandShelf>
{
static Kind getKind () { return kindBandShelf; }
static const char* getName() { return "RBJ Band Shelf"; }
};

struct AllPass : TypeI <RBJ::AllPass>
{
static Kind getKind () { return kindOther; }
static const char* getName() { return "RBJ All Pass"; }
};

}

}

}

#endif

+ 129
- 0
ports-juce6/roth-air/DspFilters/RootFinder.h View File

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

"A Collection of Useful C++ Classes for Digital Signal Processing"
By Vincent Falco

Official project location:
http://code.google.com/p/dspfilterscpp/

See Documentation.cpp for contact information, notes, and bibliography.

--------------------------------------------------------------------------------

License: MIT License (http://www.opensource.org/licenses/mit-license.php)
Copyright (c) 2009 by Vincent Falco

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.

*******************************************************************************/

#ifndef DSPFILTERS_ROOTFINDER_H
#define DSPFILTERS_ROOTFINDER_H

#include "DspFilters/Common.h"
#include "DspFilters/Types.h"

namespace Dsp {

//
// Finds the complex roots of the given polynomial with
// complex-valued coefficients using a numerical method.
//

class RootFinderBase
{
public:
struct Array
{
Array (int max, complex_t* values)
// : m_max (max)
// , m_values (values)
{
}

//complex_t& operator[] (int index)
//{
//};
};

//
// Find roots of polynomial f(x)=a[0]+a[1]*x+a[2]*x^2...+a[degree]*x^degree
// The input coefficients are set using coef()[].
// The solutions are placed in roots.
//
void solve (int degree,
bool polish = true,
bool doSort = true);

// Evaluates the polynomial at x
complex_t eval (int degree,
const complex_t& x);

// Direct access to the input coefficient array of size degree+1.
complex_t* coef()
{
return m_a;
}

// Direct access to the resulting roots array of size degree
complex_t* root()
{
return m_root;
}

// sort the roots by descending imaginary part
void sort (int degree);

private:
// Improves x as a root using Laguerre's method.
// The input coefficient array has degree+1 elements.
void laguerre (int degree,
complex_t a[],
complex_t& x,
int& its);

protected:
int m_maxdegree;
complex_t* m_a; // input coefficients (m_maxdegree+1 elements)
complex_t* m_ad; // copy of deflating coefficients
complex_t* m_root; // array of roots (maxdegree elements)
};

//------------------------------------------------------------------------------

template<int maxdegree>
struct RootFinder : RootFinderBase
{
RootFinder()
{
m_maxdegree = maxdegree;
m_a = m_a0;
m_ad = m_ad0;
m_root = m_r;
}

private:
complex_t m_a0 [maxdegree+1];
complex_t m_ad0[maxdegree+1];
complex_t m_r [maxdegree];
};

}

#endif

+ 155
- 0
ports-juce6/roth-air/DspFilters/SmoothedFilter.h View File

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

"A Collection of Useful C++ Classes for Digital Signal Processing"
By Vincent Falco

Official project location:
http://code.google.com/p/dspfilterscpp/

See Documentation.cpp for contact information, notes, and bibliography.

--------------------------------------------------------------------------------

License: MIT License (http://www.opensource.org/licenses/mit-license.php)
Copyright (c) 2009 by Vincent Falco

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.

*******************************************************************************/

#ifndef DSPFILTERS_SMOOTHEDFILTER_H
#define DSPFILTERS_SMOOTHEDFILTER_H

#include "DspFilters/Common.h"
#include "DspFilters/Filter.h"
#include <algorithm>

namespace Dsp {

/*
* Implements smooth modulation of time-varying filter parameters
*
*/
template <class DesignClass,
int Channels,
class StateType = DirectFormII>
class SmoothedFilterDesign
: public FilterDesign <DesignClass,
Channels,
StateType>
{
public:
typedef FilterDesign <DesignClass, Channels, StateType> filter_type_t;

SmoothedFilterDesign (int transitionSamples)
: m_transitionSamples (transitionSamples)
, m_remainingSamples (-1) // first time flag
{
}

// Process a block of samples.
template <typename Sample>
void processBlock (int numSamples,
Sample* const* destChannelArray)
{
const int numChannels = this->getNumChannels();

// If this goes off it means setup() was never called
assert (m_remainingSamples >= 0);

// first handle any transition samples
int remainingSamples = std::min (m_remainingSamples, numSamples);

if (remainingSamples > 0)
{
// interpolate parameters for each sample
const double t = 1. / m_remainingSamples;
double dp[maxParameters];
for (int i = 0; i < DesignClass::NumParams; ++i)
dp[i] = (this->getParams()[i] - m_transitionParams[i]) * t;

for (int n = 0; n < remainingSamples; ++n)
{
for (int i = DesignClass::NumParams; --i >=0;)
m_transitionParams[i] += dp[i];

m_transitionFilter.setParams (m_transitionParams);
for (int i = numChannels; --i >= 0;)
{
Sample* dest = destChannelArray[i]+n;
*dest = this->m_state[i].process (*dest, m_transitionFilter);
}
}

m_remainingSamples -= remainingSamples;

if (m_remainingSamples == 0)
m_transitionParams = this->getParams();
}

// do what's left
if (numSamples - remainingSamples > 0)
{
// no transition
for (int i = 0; i < numChannels; ++i)
this->m_design.process (numSamples - remainingSamples,
destChannelArray[i] + remainingSamples,
this->m_state[i]);
}
}

void process (int numSamples, float* const* arrayOfChannels)
{
processBlock (numSamples, arrayOfChannels);
}

void process (int numSamples, double* const* arrayOfChannels)
{
processBlock (numSamples, arrayOfChannels);
}

protected:
void doSetParams (const Params& parameters)
{
if (m_remainingSamples >= 0)
{
m_remainingSamples = m_transitionSamples;
}
else
{
// first time
m_remainingSamples = 0;
m_transitionParams = parameters;
}

filter_type_t::doSetParams (parameters);
}

protected:
Params m_transitionParams;
DesignClass m_transitionFilter;
int m_transitionSamples;

int m_remainingSamples; // remaining transition samples
};

}

#endif

+ 323
- 0
ports-juce6/roth-air/DspFilters/State.h View File

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

"A Collection of Useful C++ Classes for Digital Signal Processing"
By Vincent Falco

Official project location:
http://code.google.com/p/dspfilterscpp/

See Documentation.cpp for contact information, notes, and bibliography.

--------------------------------------------------------------------------------

License: MIT License (http://www.opensource.org/licenses/mit-license.php)
Copyright (c) 2009 by Vincent Falco

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.

*******************************************************************************/

#ifndef DSPFILTERS_STATE_H
#define DSPFILTERS_STATE_H

#include "DspFilters/Common.h"
#include "DspFilters/Biquad.h"

#include <stdexcept>

namespace Dsp {

/*
* Various forms of state information required to
* process channels of actual sample data.
*
*/

//------------------------------------------------------------------------------

/*
* State for applying a second order section to a sample using Direct Form I
*
* Difference equation:
*
* y[n] = (b0/a0)*x[n] + (b1/a0)*x[n-1] + (b2/a0)*x[n-2]
* - (a1/a0)*y[n-1] - (a2/a0)*y[n-2]
*/
class DirectFormI
{
public:
DirectFormI ()
{
reset();
}

void reset ()
{
m_x1 = 0;
m_x2 = 0;
m_y1 = 0;
m_y2 = 0;
}

template <typename Sample>
inline Sample process1 (const Sample in,
const BiquadBase& s,
const double vsa) // very small amount
{
double out = s.m_b0*in + s.m_b1*m_x1 + s.m_b2*m_x2
- s.m_a1*m_y1 - s.m_a2*m_y2
+ vsa;
m_x2 = m_x1;
m_y2 = m_y1;
m_x1 = in;
m_y1 = out;

return static_cast<Sample> (out);
}

protected:
double m_x2; // x[n-2]
double m_y2; // y[n-2]
double m_x1; // x[n-1]
double m_y1; // y[n-1]
};

//------------------------------------------------------------------------------

/*
* State for applying a second order section to a sample using Direct Form II
*
* Difference equation:
*
* v[n] = x[n] - (a1/a0)*v[n-1] - (a2/a0)*v[n-2]
* y(n) = (b0/a0)*v[n] + (b1/a0)*v[n-1] + (b2/a0)*v[n-2]
*
*/
class DirectFormII
{
public:
DirectFormII ()
{
reset ();
}

void reset ()
{
m_v1 = 0;
m_v2 = 0;
}

template <typename Sample>
Sample process1 (const Sample in,
const BiquadBase& s,
const double vsa)
{
double w = in - s.m_a1*m_v1 - s.m_a2*m_v2 + vsa;
double out = s.m_b0*w + s.m_b1*m_v1 + s.m_b2*m_v2;

m_v2 = m_v1;
m_v1 = w;

return static_cast<Sample> (out);
}

private:
double m_v1; // v[-1]
double m_v2; // v[-2]
};

//------------------------------------------------------------------------------

/*
* Transposed Direct Form I and II
* by lubomir i. ivanov (neolit123 [at] gmail)
*
* Reference:
* http://www.kvraudio.com/forum/viewtopic.php?p=4430351
*
*/

// I think this one is broken
class TransposedDirectFormI
{
public:
TransposedDirectFormI ()
{
reset ();
}

void reset ()
{
m_v = 0;
m_s1 = 0;
m_s1_1 = 0;
m_s2 = 0;
m_s2_1 = 0;
m_s3 = 0;
m_s3_1 = 0;
m_s4 = 0;
m_s4_1 = 0;
}

template <typename Sample>
inline Sample process1 (const Sample in,
const BiquadBase& s,
const double vsa)
{
double out;

// can be: in += m_s1_1;
m_v = in + m_s1_1;
out = s.m_b0*m_v + m_s3_1;
m_s1 = m_s2_1 - s.m_a1*m_v;
m_s2 = -s.m_a2*m_v;
m_s3 = s.m_b1*m_v + m_s4_1;
m_s4 = s.m_b2*m_v;

m_s4_1 = m_s4;
m_s3_1 = m_s3;
m_s2_1 = m_s2;
m_s1_1 = m_s1;

return static_cast<Sample> (out);
}

private:
double m_v;
double m_s1;
double m_s1_1;
double m_s2;
double m_s2_1;
double m_s3;
double m_s3_1;
double m_s4;
double m_s4_1;
};

//------------------------------------------------------------------------------

class TransposedDirectFormII
{
public:
TransposedDirectFormII ()
{
reset ();
}

void reset ()
{
m_s1 = 0;
m_s1_1 = 0;
m_s2 = 0;
m_s2_1 = 0;
}

template <typename Sample>
inline Sample process1 (const Sample in,
const BiquadBase& s,
const double vsa)
{
double out;

out = m_s1_1 + s.m_b0*in + vsa;
m_s1 = m_s2_1 + s.m_b1*in - s.m_a1*out;
m_s2 = s.m_b2*in - s.m_a2*out;
m_s1_1 = m_s1;
m_s2_1 = m_s2;

return static_cast<Sample> (out);
}

private:
double m_s1;
double m_s1_1;
double m_s2;
double m_s2_1;
};

//------------------------------------------------------------------------------

// Holds an array of states suitable for multi-channel processing
template <int Channels, class StateType>
class ChannelsState
{
public:
ChannelsState ()
{
}

const int getNumChannels() const
{
return Channels;
}

void reset ()
{
for (int i = 0; i < Channels; ++i)
m_state[i].reset();
}

StateType& operator[] (int index)
{
assert (index >= 0 && index < Channels);
return m_state[index];
}

template <class Filter, typename Sample>
void process (int numSamples,
Sample* const* arrayOfChannels,
Filter& filter)
{
for (int i = 0; i < Channels; ++i)
filter.process (numSamples, arrayOfChannels[i], m_state[i]);
}

private:
StateType m_state[Channels];
};

// Empty state, can't process anything
template <class StateType>
class ChannelsState <0, StateType>
{
public:
const int getNumChannels() const
{
return 0;
}

void reset ()
{
throw std::logic_error ("attempt to reset empty ChannelState");
}

template <class FilterDesign, typename Sample>
void process (int numSamples,
Sample* const* arrayOfChannels,
FilterDesign& filter)
{
throw std::logic_error ("attempt to process empty ChannelState");
}
};

//------------------------------------------------------------------------------

}

#endif

+ 139
- 0
ports-juce6/roth-air/DspFilters/Types.h View File

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

"A Collection of Useful C++ Classes for Digital Signal Processing"
By Vincent Falco

Official project location:
http://code.google.com/p/dspfilterscpp/

See Documentation.cpp for contact information, notes, and bibliography.

--------------------------------------------------------------------------------

License: MIT License (http://www.opensource.org/licenses/mit-license.php)
Copyright (c) 2009 by Vincent Falco

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.

*******************************************************************************/

#ifndef DSPFILTERS_TYPES_H
#define DSPFILTERS_TYPES_H

#include "DspFilters/Common.h"
#include "DspFilters/MathSupplement.h"

namespace Dsp {

// A conjugate or real pair
struct ComplexPair : complex_pair_t
{
ComplexPair ()
{
}

explicit ComplexPair (const complex_t& c1)
: complex_pair_t (c1, 0.)
{
assert (isReal());
}

ComplexPair (const complex_t& c1,
const complex_t& c2)
: complex_pair_t (c1, c2)
{
}

bool isConjugate () const
{
return second == std::conj (first);
}

bool isReal () const
{
return first.imag() == 0 && second.imag() == 0;
}

// Returns true if this is either a conjugate pair,
// or a pair of reals where neither is zero.
bool isMatchedPair () const
{
if (first.imag() != 0)
return second == std::conj (first);
else
return second.imag () == 0 &&
second.real () != 0 &&
first.real () != 0;
}

bool is_nan () const
{
return Dsp::is_nan (first) || Dsp::is_nan (second);
}
};

// A pair of pole/zeros. This fits in a biquad (but is missing the gain)
struct PoleZeroPair
{
ComplexPair poles;
ComplexPair zeros;

PoleZeroPair () { }

// single pole/zero
PoleZeroPair (const complex_t& p, const complex_t& z)
: poles (p), zeros (z)
{
}

// pole/zero pair
PoleZeroPair (const complex_t& p1, const complex_t& z1,
const complex_t& p2, const complex_t& z2)
: poles (p1, p2)
, zeros (z1, z2)
{
}

bool isSinglePole () const
{
return poles.second == 0. && zeros.second == 0.;
}

bool is_nan () const
{
return poles.is_nan() || zeros.is_nan();
}
};

// Identifies the general class of filter
enum Kind
{
kindLowPass,
kindHighPass,
kindBandPass,
kindBandStop,
kindLowShelf,
kindHighShelf,
kindBandShelf,
kindOther
};

}

#endif

+ 730
- 0
ports-juce6/roth-air/DspFilters/Utilities.h View File

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

"A Collection of Useful C++ Classes for Digital Signal Processing"
By Vincent Falco

Official project location:
http://code.google.com/p/dspfilterscpp/

See Documentation.cpp for contact information, notes, and bibliography.

--------------------------------------------------------------------------------

License: MIT License (http://www.opensource.org/licenses/mit-license.php)
Copyright (c) 2009 by Vincent Falco

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.

*******************************************************************************/

#ifndef DSPFILTERS_UTILITIES_H
#define DSPFILTERS_UTILITIES_H

#include "DspFilters/Common.h"

namespace Dsp {

/*
* Utilities
*
* These routines are handy for manipulating buffers of samples.
*
*/

//------------------------------------------------------------------------------

// Add src samples to dest, without clip or overflow checking.
template <class Td,
class Ts>
void add (int samples,
Td* dest,
Ts const* src,
int destSkip = 0,
int srcSkip = 0)
{
if (srcSkip !=0 || destSkip != 0)
{
++srcSkip;
++destSkip;
while (--samples >= 0)
{
*dest = static_cast<Td>(*src);
dest += destSkip;
src += srcSkip;
}
}
else
{
while (--samples >= 0)
*dest++ += static_cast<Td>(*src++);
}
}

// Multichannel add
template <typename Td,
typename Ts>
void add (int channels,
int samples,
Td* const* dest,
Ts const* const* src)
{
for (int i = channels; --i >= 0;)
add (samples, dest[i], src[i]);
}

//--------------------------------------------------------------------------

// Copy samples from src to dest, which may not overlap. Performs an implicit
// type conversion if Ts and Td are different (for example, float to double).
template <typename Td,
typename Ts>
void copy (int samples,
Td* dest,
Ts const* src,
int destSkip = 0,
int srcSkip = 0)
{
if (srcSkip != 0)
{
if (destSkip != 0)
{
++srcSkip;
++destSkip;
while (--samples >= 0)
{
*dest++ = *src++;
dest += destSkip;
src += srcSkip;
}
}
else
{
++srcSkip;
while (--samples >= 0)
{
*dest++ = *src++;
src += srcSkip;
}
}
}
else if (destSkip != 0)
{
++destSkip;
while (--samples >= 0)
{
*dest = *src++;
dest += destSkip;
}
}
else
{
while (--samples >= 0)
*dest++ = *src++;
}
}

// Wrapper that uses memcpy if there is no skip and the types are the same
template <typename Ty>
void copy (int samples,
Ty* dest,
Ty const* src,
int destSkip = 0,
int srcSkip = 0)
{
if (destSkip != 0 || srcSkip != 0)
copy<Ty,Ty> (samples, dest, src, destSkip, srcSkip);
else
::memcpy (dest, src, samples * sizeof(src[0]));
}

// Copy a set of channels from src to dest, with implicit type conversion.
template <typename Td,
typename Ts>
void copy (int channels,
int samples,
Td* const* dest,
Ts const* const* src,
int destSkip = 0,
int srcSkip = 0)
{
for (int i = channels; --i >= 0;)
copy (samples, dest[i], src[i], destSkip, srcSkip);
}

//--------------------------------------------------------------------------

// Deinterleave channels. Performs implicit type conversion.
template <typename Td, typename Ts>
void deinterleave (int channels,
int samples,
Td* const* dest,
Ts const* src)
{
assert (channels > 1);

switch (channels)
{
case 2:
{
Td* l = dest[0];
Td* r = dest[1];
int n = (samples + 7) / 8;
switch (samples % 8)
{
case 0: do
{
*l++ = *src++; *r++ = *src++;
case 7: *l++ = *src++; *r++ = *src++;
case 6: *l++ = *src++; *r++ = *src++;
case 5: *l++ = *src++; *r++ = *src++;
case 4: *l++ = *src++; *r++ = *src++;
case 3: *l++ = *src++; *r++ = *src++;
case 2: *l++ = *src++; *r++ = *src++;
case 1: *l++ = *src++; *r++ = *src++;
}
while (--n > 0);
}
}
break;

default:
{
for (int i = channels; --i >= 0;)
copy (samples, dest[i], src + i, 0, channels - 1);
}
break;
};
}

// Convenience for a stereo pair of channels
template <typename Td,
typename Ts>
void deinterleave (int samples,
Td* left,
Td* right,
Ts const* src)
{
Td* dest[2];
dest[0] = left;
dest[1] = right;
deinterleave (2, samples, dest, src);
}

//--------------------------------------------------------------------------

// Fade dest
template <typename Td,
typename Ty>
void fade (int samples,
Td* dest,
Ty start = 0,
Ty end = 1)
{
Ty t = start;
Ty dt = (end - start) / samples;

while (--samples >= 0)
{
*dest++ *= t;
t += dt;
}
}

// Fade dest cannels
template <typename Td,
typename Ty>
void fade (int channels,
int samples,
Td* const* dest,
Ty start = 0,
Ty end = 1)
{
for (int i = channels; --i >= 0;)
fade (samples, dest[i], start, end);
}

// Fade src into dest
template <typename Td,
typename Ts,
typename Ty>
void fade (int samples,
Td* dest,
Ts const* src,
Ty start = 0,
Ty end = 1)
{
Ty t = start;
Ty dt = (end - start) / samples;

while (--samples >= 0)
{
*dest++ = static_cast<Td>(*dest + t * (*src++ - *dest));
t += dt;
}
}

// Fade src channels into dest channels
template <typename Td,
typename Ts,
typename Ty>
void fade (int channels,
int samples,
Td* const* dest,
Ts const* const* src,
Ty start = 0,
Ty end = 1)
{
for (int i = channels; --i >= 0;)
fade (samples, dest[i], src[i], start, end);
}

//--------------------------------------------------------------------------

// Interleave separate channels from source pointers to destination
// (Destination requires channels*frames samples of storage). Performs
// implicit type conversion.
template <typename Td,
typename Ts>
void interleave (int channels,
size_t samples,
Td* dest,
Ts const* const* src)
{
assert (channels>1);

if (samples==0)
return;

switch (channels)
{
case 2:
{
const Ts* l = src[0];
const Ts* r = src[1];

// note that Duff's Device only works when samples>0
int n = (samples + 7) / 8;
switch (samples % 8)
{
case 0: do
{
*dest++ = *l++; *dest++ = *r++;
case 7: *dest++ = *l++; *dest++ = *r++;
case 6: *dest++ = *l++; *dest++ = *r++;
case 5: *dest++ = *l++; *dest++ = *r++;
case 4: *dest++ = *l++; *dest++ = *r++;
case 3: *dest++ = *l++; *dest++ = *r++;
case 2: *dest++ = *l++; *dest++ = *r++;
case 1: *dest++ = *l++; *dest++ = *r++;
}
while (--n > 0);
}
}
break;

default:
{
for (int i = channels; --i >= 0;)
copy (samples, dest + i, src[i], channels - 1, 0);
}
break;
};
}

//--------------------------------------------------------------------------

// Convenience for a stereo channel pair
template <typename Td,
typename Ts>
void interleave (int samples,
Td* dest,
Ts const* left,
Ts const* right)
{
const Ts* src[2];
src[0] = left;
src[1] = right;
interleave (2, samples, dest, src);
}

//--------------------------------------------------------------------------

// Multiply samples by a constant, without clip or overflow checking.
template <typename Td,
typename Ty>
void multiply (int samples,
Td* dest,
Ty factor,
int destSkip = 0)
{
if (destSkip != 0)
{
++destSkip;
while (--samples >= 0)
{
*dest = static_cast<Td>(*dest * factor);
dest += destSkip;
}
}
else
{
while (--samples >= 0)
*dest++ = static_cast<Td>(*dest * factor);
}
}

// Multiply a set of channels by a constant.
template <typename Td,
typename Ty>
void multiply (int channels,
int samples,
Td* const* dest,
Ty factor,
int destSkip = 0)
{
for (int i = channels; --i >= 0;)
multiply (samples, dest[i], factor, destSkip);
}

//--------------------------------------------------------------------------

// Copy samples from src to dest in reversed order. Performs implicit
// type conversion. src and dest may not overlap.
template <typename Td,
typename Ts>
void reverse (int samples,
Td* dest,
Ts const* src,
int destSkip = 0,
int srcSkip = 0 )
{
src += (srcSkip + 1) * samples;

if (srcSkip != 0 || destSkip == 0)
{
++srcSkip;
++destSkip;
while (--samples >= 0)
{
src -= srcSkip;
*dest = *src;
dest += destSkip;
}
}
else
{
while (--samples >= 0)
*dest++ = *--src;
}
}

template <typename Td, typename Ts>
void reverse (int channels, size_t frames, Td* const* dest, const Ts* const* src)
{
for (int i = channels; --i >= 0;)
reverse (frames, dest[i], src[i]);
}

//--------------------------------------------------------------------------

template <typename Tn>
void to_mono (int samples, Tn* dest, Tn const* left, Tn const* right)
{
#if 1
while (samples-- > 0)
*dest++ = (*left++ + *right++) * Tn(0.70710678118654752440084436210485);
#else
while (samples-- > 0)
*dest++ = (*left++ + *right++) * Tn(0.5);
#endif
}

//--------------------------------------------------------------------------

template <typename T>
void validate (int numChannels, int numSamples, T const* const* src)
{
for (int i = 0; i < numChannels; ++i)
{
T const* p = src [i];
for (int j = numSamples; j > 0; --j)
{
T v = *p++;
assert (v < 2 && v > -2);
}
}
}

//--------------------------------------------------------------------------

#if 0
/*
* this stuff all depends on is_pod which is not always available
*
*/
namespace detail {

template <typename Ty,
bool isPod>
struct zero
{
static void process (int samples,
Ty* dest,
int destSkip)
{
if (destSkip != 0)
{
++destSkip;
while (--samples >= 0)
{
*dest = Ty();
dest += destSkip;
}
}
else
{
std::fill (dest, dest + samples, Ty());
}
}
};

template <typename Ty>
struct zero<Ty, true>
{
static void process (int samples,
Ty* dest,
int destSkip)
{
if (destSkip != 0)
zero<Ty,false>::process (samples, dest, destSkip);
else
::memset (dest, 0, samples * sizeof(dest[0]));
}
};

}

// Fill a channel with zeros. This works even if Ty is not a basic type.
template <typename Ty>
void zero (int samples,
Ty* dest,
int destSkip = 0)
{
detail::zero<Ty, tr1::is_pod<Ty>::value>::process (samples, dest, destSkip );
}

#else
// Fill a channel with zeros. This works even if Ty is not a basic type.
template <typename Ty>
void zero (int samples,
Ty* dest,
int destSkip = 0)
{
if (destSkip != 0)
{
++destSkip;
while (--samples >= 0)
{
*dest = Ty();
dest += destSkip;
}
}
else
{
std::fill (dest, dest + samples, Ty());
}
}

#endif

// Fill a set of channels with zero.
template <typename Ty>
void zero (int channels,
int samples,
Ty* const* dest,
int destSkip = 0)
{
for (int i = channels; --i >= 0;)
zero (samples, dest[i], destSkip);
}

//------------------------------------------------------------------------------

// Implementation of Brent's Method provided by
// John D. Cook (http://www.johndcook.com/)
// The return value of Minimize is the minimum of the function f.
// The location where f takes its minimum is returned in the variable minLoc.
// Notation and implementation based on Chapter 5 of Richard Brent's book
// "Algorithms for Minimization Without Derivatives".
//
// Reference:
// http://www.codeproject.com/KB/recipes/one_variable_optimize.aspx?msg=2779038

template <class TFunction>
double BrentMinimize
(
TFunction& f, // [in] objective function to minimize
double leftEnd, // [in] smaller value of bracketing interval
double rightEnd, // [in] larger value of bracketing interval
double epsilon, // [in] stopping tolerance
double& minLoc // [out] location of minimum
)
{
double d, e, m, p, q, r, tol, t2, u, v, w, fu, fv, fw, fx;
static const double c = 0.5*(3.0 - ::std::sqrt(5.0));
static const double SQRT_DBL_EPSILON = ::std::sqrt(DBL_EPSILON);

double& a = leftEnd;
double& b = rightEnd;
double& x = minLoc;

v = w = x = a + c*(b - a);
d = e = 0.0;
fv = fw = fx = f(x);
int counter = 0;
loop:
counter++;
m = 0.5*(a + b);
tol = SQRT_DBL_EPSILON*::fabs(x) + epsilon;
t2 = 2.0*tol;
// Check stopping criteria
if (::fabs(x - m) > t2 - 0.5*(b - a))
{
p = q = r = 0.0;
if (::fabs(e) > tol)
{
// fit parabola
r = (x - w)*(fx - fv);
q = (x - v)*(fx - fw);
p = (x - v)*q - (x - w)*r;
q = 2.0*(q - r);
(q > 0.0) ? p = -p : q = -q;
r = e;
e = d;
}
if (::fabs(p) < ::fabs(0.5*q*r) && p < q*(a - x) && p < q*(b - x))
{
// A parabolic interpolation step
d = p/q;
u = x + d;
// f must not be evaluated too close to a or b
if (u - a < t2 || b - u < t2)
d = (x < m) ? tol : -tol;
}
else
{
// A golden section step
e = (x < m) ? b : a;
e -= x;
d = c*e;
}
// f must not be evaluated too close to x
if (::fabs(d) >= tol)
u = x + d;
else if (d > 0.0)
u = x + tol;
else
u = x - tol;
fu = f(u);
// Update a, b, v, w, and x
if (fu <= fx)
{
(u < x) ? b = x : a = x;
v = w;
fv = fw;
w = x;
fw = fx;
x = u;
fx = fu;
}
else
{
(u < x) ? a = u : b = u;
if (fu <= fw || w == x)
{
v = w;
fv = fw;
w = u;
fw = fu;
}
else if (fu <= fv || v == x || v == w)
{
v = u;
fv = fu;
}
}
goto loop; // Yes, the dreaded goto statement. But the code
// here is faithful to Brent's orginal pseudocode.
}
return fx;
}

//------------------------------------------------------------------------------

// Tracks the peaks in the signal stream using the attack and release parameters
template <int Channels=2, typename Value=float>
class EnvelopeFollower
{
public:
EnvelopeFollower()
{
for (int i = 0; i < Channels; i++)
m_env[i]=0;
}

Value operator[] (int channel) const
{
return m_env[channel];
}

void Setup (int sampleRate, double attackMs, double releaseMs)
{
m_a = pow (0.01, 1.0 / (attackMs * sampleRate * 0.001));
m_r = pow (0.01, 1.0 / (releaseMs * sampleRate * 0.001));
}

void Process (size_t samples, const Value** src)
{
for( int i=0; i<Channels; i++ )
{
const Value* cur = src[i];

double e = m_env[i];
for (int n = samples; n; n--)
{
double v = ::fabs(*cur++);
if (v > e)
e = m_a * (e - v) + v;
else
e = m_r * (e - v) + v;
}
m_env[i]=e;
}
}

double m_env[Channels];

protected:
double m_a;
double m_r;
};

}

#endif

+ 224
- 0
ports-juce6/roth-air/DspFilters/source/Bessel.cpp View File

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

"A Collection of Useful C++ Classes for Digital Signal Processing"
By Vincent Falco

Official project location:
http://code.google.com/p/dspfilterscpp/

See Documentation.cpp for contact information, notes, and bibliography.

--------------------------------------------------------------------------------

License: MIT License (http://www.opensource.org/licenses/mit-license.php)
Copyright (c) 2009 by Vincent Falco

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 "DspFilters/Common.h"
#include "DspFilters/Bessel.h"
#include "DspFilters/RootFinder.h"

namespace Dsp {

namespace Bessel {

// returns fact(n) = n!
static double fact (int n)
{
if (n == 0)
return 1;

double y = n;
for (double m = n; --m;)
y *= m;

return y;
}

// returns the k-th zero based coefficient of the reverse bessel polynomial of degree n
static double reversebessel (int k, int n)
{
return fact (2 * n - k) /
((fact (n - k) * fact(k)) * pow(2., n - k));
}

//------------------------------------------------------------------------------

AnalogLowPass::AnalogLowPass ()
: m_numPoles (-1)
{
setNormal (0, 1);
}

void AnalogLowPass::design (int numPoles,
WorkspaceBase* w)
{
if (m_numPoles != numPoles)
{
m_numPoles = numPoles;

reset ();

RootFinderBase& solver (w->roots);
for (int i = 0; i < numPoles + 1; ++i)
solver.coef()[i] = reversebessel (i, numPoles);
solver.solve (numPoles);

const int pairs = numPoles / 2;
for (int i = 0; i < pairs; ++i)
{
complex_t c = solver.root()[i];
addPoleZeroConjugatePairs (c, infinity());
}

if (numPoles & 1)
add (solver.root()[pairs].real(), infinity());
}
}

//------------------------------------------------------------------------------

AnalogLowShelf::AnalogLowShelf ()
: m_numPoles (-1)
{
setNormal (doublePi, 1);
}

void AnalogLowShelf::design (int numPoles,
double gainDb,
WorkspaceBase* w)
{
if (m_numPoles != numPoles ||
m_gainDb != gainDb)
{
m_numPoles = numPoles;
m_gainDb = gainDb;

reset ();

const double G = pow (10., gainDb / 20) - 1;

RootFinderBase& poles (w->roots);
for (int i = 0; i < numPoles + 1; ++i)
poles.coef()[i] = reversebessel (i, numPoles);
poles.solve (numPoles);

RootFinder<50> zeros;
for (int i = 0; i < numPoles + 1; ++i)
zeros.coef()[i] = reversebessel (i, numPoles);
double a0 = reversebessel (0, numPoles);
zeros.coef()[0] += G * a0;
zeros.solve (numPoles);

const int pairs = numPoles / 2;
for (int i = 0; i < pairs; ++i)
{
complex_t p = poles.root()[i];
complex_t z = zeros.root()[i];
addPoleZeroConjugatePairs (p, z);
}

if (numPoles & 1)
add (poles.root()[pairs].real(), zeros.root()[pairs].real());
}
}

//------------------------------------------------------------------------------

void LowPassBase::setup (int order,
double sampleRate,
double cutoffFrequency,
WorkspaceBase* w)
{
m_analogProto.design (order, w);

LowPassTransform (cutoffFrequency / sampleRate,
m_digitalProto,
m_analogProto);

Cascade::setLayout (m_digitalProto);
}

void HighPassBase::setup (int order,
double sampleRate,
double cutoffFrequency,
WorkspaceBase* w)
{
m_analogProto.design (order, w);

HighPassTransform (cutoffFrequency / sampleRate,
m_digitalProto,
m_analogProto);

Cascade::setLayout (m_digitalProto);
}

void BandPassBase::setup (int order,
double sampleRate,
double centerFrequency,
double widthFrequency,
WorkspaceBase* w)
{
m_analogProto.design (order, w);

BandPassTransform (centerFrequency / sampleRate,
widthFrequency / sampleRate,
m_digitalProto,
m_analogProto);

Cascade::setLayout (m_digitalProto);
}

void BandStopBase::setup (int order,
double sampleRate,
double centerFrequency,
double widthFrequency,
WorkspaceBase* w)
{
m_analogProto.design (order, w);

BandStopTransform (centerFrequency / sampleRate,
widthFrequency / sampleRate,
m_digitalProto,
m_analogProto);

Cascade::setLayout (m_digitalProto);
}

void LowShelfBase::setup (int order,
double sampleRate,
double cutoffFrequency,
double gainDb,
WorkspaceBase* w)
{
m_analogProto.design (order, gainDb, w);

LowPassTransform (cutoffFrequency / sampleRate,
m_digitalProto,
m_analogProto);

Cascade::setLayout (m_digitalProto);
}

}

}

+ 236
- 0
ports-juce6/roth-air/DspFilters/source/Biquad.cpp View File

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

"A Collection of Useful C++ Classes for Digital Signal Processing"
By Vincent Falco

Official project location:
http://code.google.com/p/dspfilterscpp/

See Documentation.cpp for contact information, notes, and bibliography.

--------------------------------------------------------------------------------

License: MIT License (http://www.opensource.org/licenses/mit-license.php)
Copyright (c) 2009 by Vincent Falco

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 "DspFilters/Common.h"
#include "DspFilters/MathSupplement.h"
#include "DspFilters/Biquad.h"

namespace Dsp {

BiquadPoleState::BiquadPoleState (const BiquadBase& s)
{
const double a0 = s.getA0 ();
const double a1 = s.getA1 ();
const double a2 = s.getA2 ();
const double b0 = s.getB0 ();
const double b1 = s.getB1 ();
const double b2 = s.getB2 ();

if (a2 == 0 && b2 == 0)
{
// single pole
poles.first = -a1;
zeros.first = -b0 / b1;
poles.second = 0;
zeros.second = 0;
}
else
{
{
const complex_t c = sqrt (complex_t (a1 * a1 - 4 * a0 * a2, 0));
double d = 2. * a0;
poles.first = -(a1 + c) / d;
poles.second = (c - a1) / d;
assert (!poles.is_nan());
}

{
const complex_t c = sqrt (complex_t (
b1 * b1 - 4 * b0 * b2, 0));
double d = 2. * b0;
zeros.first = -(b1 + c) / d;
zeros.second = (c - b1) / d;
assert (!zeros.is_nan());
}
}

gain = b0 / a0;
}

//------------------------------------------------------------------------------

complex_t BiquadBase::response (double normalizedFrequency) const
{
const double a0 = getA0 ();
const double a1 = getA1 ();
const double a2 = getA2 ();
const double b0 = getB0 ();
const double b1 = getB1 ();
const double b2 = getB2 ();

const double w = 2 * doublePi * normalizedFrequency;
const complex_t czn1 = std::polar (1., -w);
const complex_t czn2 = std::polar (1., -2 * w);
complex_t ch (1);
complex_t cbot (1);

complex_t ct (b0/a0);
complex_t cb (1);
ct = addmul (ct, b1/a0, czn1);
ct = addmul (ct, b2/a0, czn2);
cb = addmul (cb, a1/a0, czn1);
cb = addmul (cb, a2/a0, czn2);
ch *= ct;
cbot *= cb;

return ch / cbot;
}

std::vector<PoleZeroPair> BiquadBase::getPoleZeros () const
{
std::vector<PoleZeroPair> vpz;
BiquadPoleState bps (*this);
vpz.push_back (bps);
return vpz;
}

void BiquadBase::setCoefficients (double a0, double a1, double a2,
double b0, double b1, double b2)
{
assert (!Dsp::is_nan (a0) && !Dsp::is_nan (a1) && !Dsp::is_nan (a2) &&
!Dsp::is_nan (b0) && !Dsp::is_nan (b1) && !Dsp::is_nan (b2));

m_a0 = a0;
m_a1 = a1/a0;
m_a2 = a2/a0;
m_b0 = b0/a0;
m_b1 = b1/a0;
m_b2 = b2/a0;
}

void BiquadBase::setOnePole (complex_t pole, complex_t zero)
{
#if 0
pole = adjust_imag (pole);
zero = adjust_imag (zero);
#else
assert (pole.imag() == 0);
assert (zero.imag() == 0);
#endif
const double a0 = 1;
const double a1 = -pole.real();
const double a2 = 0;
const double b0 = -zero.real();
const double b1 = 1;
const double b2 = 0;

setCoefficients (a0, a1, a2, b0, b1, b2);
}

void BiquadBase::setTwoPole (complex_t pole1, complex_t zero1,
complex_t pole2, complex_t zero2)
{
#if 0
pole1 = adjust_imag (pole1);
pole2 = adjust_imag (pole2);
zero1 = adjust_imag (zero1);
zero2 = adjust_imag (zero2);
#endif

const double a0 = 1;
double a1;
double a2;

if (pole1.imag() != 0)
{
assert (pole2 == std::conj (pole1));

a1 = -2 * pole1.real();
a2 = std::norm (pole1);
}
else
{
assert (pole2.imag() == 0);

a1 = -(pole1.real() + pole2.real());
a2 = pole1.real() * pole2.real();
}

const double b0 = 1;
double b1;
double b2;

if (zero1.imag() != 0)
{
assert (zero2 == std::conj (zero1));

b1 = -2 * zero1.real();
b2 = std::norm (zero1);
}
else
{
assert (zero2.imag() == 0);

b1 = -(zero1.real() + zero2.real());
b2 = zero1.real() * zero2.real();
}

setCoefficients (a0, a1, a2, b0, b1, b2);
}

void BiquadBase::setPoleZeroForm (const BiquadPoleState& bps)
{
setPoleZeroPair (bps);
applyScale (bps.gain);
}

void BiquadBase::setIdentity ()
{
setCoefficients (1, 0, 0, 1, 0, 0);
}

void BiquadBase::applyScale (double scale)
{
m_b0 *= scale;
m_b1 *= scale;
m_b2 *= scale;
}

//------------------------------------------------------------------------------

Biquad::Biquad ()
{
}

// Construct a second order section from a pair of poles and zeroes
Biquad::Biquad (const BiquadPoleState& bps)
{
setPoleZeroForm (bps);
}

//------------------------------------------------------------------------------

}

+ 212
- 0
ports-juce6/roth-air/DspFilters/source/Butterworth.cpp View File

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

"A Collection of Useful C++ Classes for Digital Signal Processing"
By Vincent Falco

Official project location:
http://code.google.com/p/dspfilterscpp/

See Documentation.cpp for contact information, notes, and bibliography.

--------------------------------------------------------------------------------

License: MIT License (http://www.opensource.org/licenses/mit-license.php)
Copyright (c) 2009 by Vincent Falco

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 "DspFilters/Common.h"
#include "DspFilters/Butterworth.h"

namespace Dsp {

namespace Butterworth {

AnalogLowPass::AnalogLowPass ()
: m_numPoles (-1)
{
setNormal (0, 1);
}

void AnalogLowPass::design (int numPoles)
{
if (m_numPoles != numPoles)
{
m_numPoles = numPoles;

reset ();

const double n2 = 2 * numPoles;
const int pairs = numPoles / 2;
for (int i = 0; i < pairs; ++i)
{
complex_t c = std::polar (1., doublePi_2 + (2 * i + 1) * doublePi / n2);
addPoleZeroConjugatePairs (c, infinity());
}

if (numPoles & 1)
add (-1, infinity());
}
}

//------------------------------------------------------------------------------

AnalogLowShelf::AnalogLowShelf ()
: m_numPoles (-1)
{
setNormal (doublePi, 1);
}

void AnalogLowShelf::design (int numPoles, double gainDb)
{
if (m_numPoles != numPoles ||
m_gainDb != gainDb)
{
m_numPoles = numPoles;
m_gainDb = gainDb;

reset ();

const double n2 = numPoles * 2;
const double g = pow (pow (10., gainDb/20), 1. / n2);
const double gp = -1. / g;
const double gz = -g;

const int pairs = numPoles / 2;
for (int i = 1; i <= pairs; ++i)
{
const double theta = doublePi * (0.5 - (2 * i - 1) / n2);
addPoleZeroConjugatePairs (std::polar (gp, theta), std::polar (gz, theta));
}
if (numPoles & 1)
add (gp, gz);
}
}

//------------------------------------------------------------------------------

void LowPassBase::setup (int order,
double sampleRate,
double cutoffFrequency)
{
m_analogProto.design (order);

LowPassTransform (cutoffFrequency / sampleRate,
m_digitalProto,
m_analogProto);

Cascade::setLayout (m_digitalProto);
}

void HighPassBase::setup (int order,
double sampleRate,
double cutoffFrequency)
{
m_analogProto.design (order);

HighPassTransform (cutoffFrequency / sampleRate,
m_digitalProto,
m_analogProto);

Cascade::setLayout (m_digitalProto);
}

void BandPassBase::setup (int order,
double sampleRate,
double centerFrequency,
double widthFrequency)
{
m_analogProto.design (order);

BandPassTransform (centerFrequency / sampleRate,
widthFrequency / sampleRate,
m_digitalProto,
m_analogProto);

Cascade::setLayout (m_digitalProto);
}

void BandStopBase::setup (int order,
double sampleRate,
double centerFrequency,
double widthFrequency)
{
m_analogProto.design (order);

BandStopTransform (centerFrequency / sampleRate,
widthFrequency / sampleRate,
m_digitalProto,
m_analogProto);

Cascade::setLayout (m_digitalProto);
}

void LowShelfBase::setup (int order,
double sampleRate,
double cutoffFrequency,
double gainDb)
{
m_analogProto.design (order, gainDb);

LowPassTransform (cutoffFrequency / sampleRate,
m_digitalProto,
m_analogProto);

Cascade::setLayout (m_digitalProto);
}

void HighShelfBase::setup (int order,
double sampleRate,
double cutoffFrequency,
double gainDb)
{
m_analogProto.design (order, gainDb);

HighPassTransform (cutoffFrequency / sampleRate,
m_digitalProto,
m_analogProto);

Cascade::setLayout (m_digitalProto);
}

void BandShelfBase::setup (int order,
double sampleRate,
double centerFrequency,
double widthFrequency,
double gainDb)
{
m_analogProto.design (order, gainDb);

BandPassTransform (centerFrequency / sampleRate,
widthFrequency / sampleRate,
m_digitalProto,
m_analogProto);

// HACK!
m_digitalProto.setNormal (((centerFrequency/sampleRate) < 0.25) ? doublePi : 0, 1);

Cascade::setLayout (m_digitalProto);
}

}

}

+ 118
- 0
ports-juce6/roth-air/DspFilters/source/Cascade.cpp View File

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

"A Collection of Useful C++ Classes for Digital Signal Processing"
By Vincent Falco

Official project location:
http://code.google.com/p/dspfilterscpp/

See Documentation.cpp for contact information, notes, and bibliography.

--------------------------------------------------------------------------------

License: MIT License (http://www.opensource.org/licenses/mit-license.php)
Copyright (c) 2009 by Vincent Falco

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 "DspFilters/Common.h"
#include "DspFilters/Cascade.h"

namespace Dsp {

Cascade::Cascade ()
: m_numStages (0)
, m_maxStages (0)
, m_stageArray (0)
{
}

void Cascade::setCascadeStorage (const Storage& storage)
{
m_numStages = 0;
m_maxStages = storage.maxStages;
m_stageArray = storage.stageArray;
}

complex_t Cascade::response (double normalizedFrequency) const
{
double w = 2 * doublePi * normalizedFrequency;
const complex_t czn1 = std::polar (1., -w);
const complex_t czn2 = std::polar (1., -2 * w);
complex_t ch (1);
complex_t cbot (1);

const Biquad* stage = m_stageArray;
for (int i = m_numStages; --i >=0; ++stage)
{
complex_t cb (1);
complex_t ct (stage->getB0()/stage->getA0());
ct = addmul (ct, stage->getB1()/stage->getA0(), czn1);
ct = addmul (ct, stage->getB2()/stage->getA0(), czn2);
cb = addmul (cb, stage->getA1()/stage->getA0(), czn1);
cb = addmul (cb, stage->getA2()/stage->getA0(), czn2);
ch *= ct;
cbot *= cb;
}

return ch / cbot;
}

std::vector<PoleZeroPair> Cascade::getPoleZeros () const
{
std::vector<PoleZeroPair> vpz;
vpz.reserve (m_numStages);

const Stage* stage = m_stageArray;
for (int i = m_numStages; --i >=0;)
{
BiquadPoleState bps (*stage++);
assert (!bps.isSinglePole() || i == 0);
vpz.push_back (bps);
}

return vpz;
}

void Cascade::applyScale (double scale)
{
// For higher order filters it might be helpful
// to spread this factor between all the stages.
assert (m_numStages > 0);
m_stageArray->applyScale (scale);
}

void Cascade::setLayout (const LayoutBase& proto)
{
const int numPoles = proto.getNumPoles();
m_numStages = (numPoles + 1)/ 2;
assert (m_numStages <= m_maxStages);

Biquad* stage = m_stageArray;
for (int i = 0; i < m_numStages; ++i, ++stage)
stage->setPoleZeroPair (proto[i]);
applyScale (proto.getNormalGain() /
std::abs (response (proto.getNormalW() / (2 * doublePi))));
}

}


+ 272
- 0
ports-juce6/roth-air/DspFilters/source/ChebyshevI.cpp View File

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

"A Collection of Useful C++ Classes for Digital Signal Processing"
By Vincent Falco

Official project location:
http://code.google.com/p/dspfilterscpp/

See Documentation.cpp for contact information, notes, and bibliography.

--------------------------------------------------------------------------------

License: MIT License (http://www.opensource.org/licenses/mit-license.php)
Copyright (c) 2009 by Vincent Falco

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 "DspFilters/Common.h"
#include "DspFilters/ChebyshevI.h"

namespace Dsp {

namespace ChebyshevI {

AnalogLowPass::AnalogLowPass ()
: m_numPoles (-1)
{
}

void AnalogLowPass::design (int numPoles,
double rippleDb)
{
if (m_numPoles != numPoles ||
m_rippleDb != rippleDb)
{
m_numPoles = numPoles;
m_rippleDb = rippleDb;

reset ();

const double eps = std::sqrt (1. / std::exp (-rippleDb * 0.1 * doubleLn10) - 1);
const double v0 = asinh (1 / eps) / numPoles;
const double sinh_v0 = -sinh (v0);
const double cosh_v0 = cosh (v0);

const double n2 = 2 * numPoles;
const int pairs = numPoles / 2;
for (int i = 0; i < pairs; ++i)
{
const int k = 2 * i + 1 - numPoles;
double a = sinh_v0 * cos (k * doublePi / n2);
double b = cosh_v0 * sin (k * doublePi / n2);

//addPoleZero (complex_t (a, b), infinity());
//addPoleZero (complex_t (a, -b), infinity());
addPoleZeroConjugatePairs (complex_t (a, b), infinity());
}

if (numPoles & 1)
{
add (complex_t (sinh_v0, 0), infinity());
setNormal (0, 1);
}
else
{
setNormal (0, pow (10, -rippleDb/20.));
}
}
}

//------------------------------------------------------------------------------

//
// Chebyshev Type I low pass shelf prototype
// From "High-Order Digital Parametric Equalizer Design"
// Sophocles J. Orfanidis
// http://www.ece.rutgers.edu/~orfanidi/ece521/hpeq.pdf
//

AnalogLowShelf::AnalogLowShelf ()
{
setNormal (doublePi, 1);
}

void AnalogLowShelf::design (int numPoles,
double gainDb,
double rippleDb)
{
if (m_numPoles != numPoles ||
m_rippleDb != rippleDb ||
m_gainDb != gainDb)
{
m_numPoles = numPoles;
m_rippleDb = rippleDb;
m_gainDb = gainDb;

reset ();

gainDb = -gainDb;

if (rippleDb >= abs(gainDb))
rippleDb = abs (gainDb);
if (gainDb<0)
rippleDb = -rippleDb;

const double G = std::pow (10., gainDb / 20.0 );
const double Gb = std::pow (10., (gainDb - rippleDb) / 20.0);
const double G0 = 1;
const double g0 = pow (G0 , 1. / numPoles);

double eps;
if (Gb != G0 )
eps = sqrt((G*G-Gb*Gb)/(Gb*Gb-G0*G0));
else
eps = G-1; // This is surely wrong

const double b = pow (G/eps+Gb*sqrt(1+1/(eps*eps)), 1./numPoles);
const double u = log (b / g0);
const double v = log (pow (1. / eps+sqrt(1+1/(eps*eps)),1./numPoles));
const double sinh_u = sinh (u);
const double sinh_v = sinh (v);
const double cosh_u = cosh (u);
const double cosh_v = cosh (v);
const double n2 = 2 * numPoles;
const int pairs = numPoles / 2;
for (int i = 1; i <= pairs; ++i)
{
const double a = doublePi * (2 * i - 1) / n2;
const double sn = sin (a);
const double cs = cos (a);
addPoleZeroConjugatePairs (complex_t (-sn * sinh_u, cs * cosh_u),
complex_t (-sn * sinh_v, cs * cosh_v));
}

if (numPoles & 1)
add (-sinh_u, -sinh_v);
}
}

//------------------------------------------------------------------------------

void LowPassBase::setup (int order,
double sampleRate,
double cutoffFrequency,
double rippleDb)
{
m_analogProto.design (order, rippleDb);

LowPassTransform (cutoffFrequency / sampleRate,
m_digitalProto,
m_analogProto);

Cascade::setLayout (m_digitalProto);
}

void HighPassBase::setup (int order,
double sampleRate,
double cutoffFrequency,
double rippleDb)
{
m_analogProto.design (order, rippleDb);

HighPassTransform (cutoffFrequency / sampleRate,
m_digitalProto,
m_analogProto);

Cascade::setLayout (m_digitalProto);
}

void BandPassBase::setup (int order,
double sampleRate,
double centerFrequency,
double widthFrequency,
double rippleDb)
{
m_analogProto.design (order, rippleDb);

BandPassTransform (centerFrequency / sampleRate,
widthFrequency / sampleRate,
m_digitalProto,
m_analogProto);

Cascade::setLayout (m_digitalProto);
}

void BandStopBase::setup (int order,
double sampleRate,
double centerFrequency,
double widthFrequency,
double rippleDb)
{
m_analogProto.design (order, rippleDb);

BandStopTransform (centerFrequency / sampleRate,
widthFrequency / sampleRate,
m_digitalProto,
m_analogProto);

Cascade::setLayout (m_digitalProto);
}

void LowShelfBase::setup (int order,
double sampleRate,
double cutoffFrequency,
double gainDb,
double rippleDb)
{
m_analogProto.design (order, gainDb, rippleDb);

LowPassTransform (cutoffFrequency / sampleRate,
m_digitalProto,
m_analogProto);

Cascade::setLayout (m_digitalProto);
}

void HighShelfBase::setup (int order,
double sampleRate,
double cutoffFrequency,
double gainDb,
double rippleDb)
{
m_analogProto.design (order, gainDb, rippleDb);

HighPassTransform (cutoffFrequency / sampleRate,
m_digitalProto,
m_analogProto);

Cascade::setLayout (m_digitalProto);
}

void BandShelfBase::setup (int order,
double sampleRate,
double centerFrequency,
double widthFrequency,
double gainDb,
double rippleDb)
{
m_analogProto.design (order, gainDb, rippleDb);

BandPassTransform (centerFrequency / sampleRate,
widthFrequency / sampleRate,
m_digitalProto,
m_analogProto);

m_digitalProto.setNormal (((centerFrequency/sampleRate) < 0.25) ? doublePi : 0, 1);

Cascade::setLayout (m_digitalProto);
}

}

}

+ 271
- 0
ports-juce6/roth-air/DspFilters/source/ChebyshevII.cpp View File

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

"A Collection of Useful C++ Classes for Digital Signal Processing"
By Vincent Falco

Official project location:
http://code.google.com/p/dspfilterscpp/

See Documentation.cpp for contact information, notes, and bibliography.

--------------------------------------------------------------------------------

License: MIT License (http://www.opensource.org/licenses/mit-license.php)
Copyright (c) 2009 by Vincent Falco

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 "DspFilters/Common.h"
#include "DspFilters/ChebyshevII.h"

namespace Dsp {

namespace ChebyshevII {

// "Chebyshev Filter Properties"
// http://cnx.org/content/m16906/latest/

AnalogLowPass::AnalogLowPass ()
: m_numPoles (-1)
{
setNormal (0, 1);
}

void AnalogLowPass::design (int numPoles,
double stopBandDb)
{
if (m_numPoles != numPoles ||
m_stopBandDb != stopBandDb)
{
m_numPoles = numPoles;
m_stopBandDb = stopBandDb;

reset ();

const double eps = std::sqrt (1. / (std::exp (stopBandDb * 0.1 * doubleLn10) - 1));
const double v0 = asinh (1 / eps) / numPoles;
const double sinh_v0 = -sinh (v0);
const double cosh_v0 = cosh (v0);
const double fn = doublePi / (2 * numPoles);

int k = 1;
for (int i = numPoles / 2; --i >= 0; k+=2)
{
const double a = sinh_v0 * cos ((k - numPoles) * fn);
const double b = cosh_v0 * sin ((k - numPoles) * fn);
const double d2 = a * a + b * b;
const double im = 1 / cos (k * fn);
addPoleZeroConjugatePairs (complex_t (a / d2, b / d2),
complex_t (0, im));
}

if (numPoles & 1)
{
add (1 / sinh_v0, infinity());
}
}
}

//------------------------------------------------------------------------------

//
// Chebyshev Type I low pass shelf prototype
// From "High-Order Digital Parametric Equalizer Design"
// Sophocles J. Orfanidis
// http://www.ece.rutgers.edu/~orfanidi/ece521/hpeq.pdf
//

AnalogLowShelf::AnalogLowShelf ()
: m_numPoles (-1)
{
setNormal (doublePi, 1);
}

void AnalogLowShelf::design (int numPoles,
double gainDb,
double stopBandDb)
{
if (m_numPoles != numPoles ||
m_stopBandDb != stopBandDb ||
m_gainDb != gainDb)
{
m_numPoles = numPoles;
m_stopBandDb = stopBandDb;
m_gainDb = gainDb;

reset ();

gainDb = -gainDb;

if (stopBandDb >= abs(gainDb))
stopBandDb = abs (gainDb);
if (gainDb<0)
stopBandDb = -stopBandDb;

const double G = std::pow (10., gainDb / 20.0 );
const double Gb = std::pow (10., (gainDb - stopBandDb) / 20.0);
const double G0 = 1;
const double g0 = pow (G0 , 1. / numPoles);

double eps;
if (Gb != G0 )
eps = sqrt((G*G-Gb*Gb)/(Gb*Gb-G0*G0));
else
eps = G-1; // This is surely wrong

const double b = pow (G/eps+Gb*sqrt(1+1/(eps*eps)), 1./numPoles);
const double u = log (b / g0);
const double v = log (pow (1. / eps+sqrt(1+1/(eps*eps)),1./numPoles));
const double sinh_u = sinh (u);
const double sinh_v = sinh (v);
const double cosh_u = cosh (u);
const double cosh_v = cosh (v);
const double n2 = 2 * numPoles;
const int pairs = numPoles / 2;
for (int i = 1; i <= pairs; ++i)
{
const double a = doublePi * (2 * i - 1) / n2;
const double sn = sin (a);
const double cs = cos (a);
addPoleZeroConjugatePairs (complex_t (-sn * sinh_u, cs * cosh_u),
complex_t (-sn * sinh_v, cs * cosh_v));
}

if (numPoles & 1)
add (-sinh_u, -sinh_v);
}
}

//------------------------------------------------------------------------------

void LowPassBase::setup (int order,
double sampleRate,
double cutoffFrequency,
double stopBandDb)
{
m_analogProto.design (order, stopBandDb);

LowPassTransform (cutoffFrequency / sampleRate,
m_digitalProto,
m_analogProto);

Cascade::setLayout (m_digitalProto);
}

void HighPassBase::setup (int order,
double sampleRate,
double cutoffFrequency,
double stopBandDb)
{
m_analogProto.design (order, stopBandDb);

HighPassTransform (cutoffFrequency / sampleRate,
m_digitalProto,
m_analogProto);

Cascade::setLayout (m_digitalProto);
}

void BandPassBase::setup (int order,
double sampleRate,
double centerFrequency,
double widthFrequency,
double stopBandDb)
{
m_analogProto.design (order, stopBandDb);

BandPassTransform (centerFrequency / sampleRate,
widthFrequency / sampleRate,
m_digitalProto,
m_analogProto);

Cascade::setLayout (m_digitalProto);
}

void BandStopBase::setup (int order,
double sampleRate,
double centerFrequency,
double widthFrequency,
double stopBandDb)
{
m_analogProto.design (order, stopBandDb);

BandStopTransform (centerFrequency / sampleRate,
widthFrequency / sampleRate,
m_digitalProto,
m_analogProto);

Cascade::setLayout (m_digitalProto);
}

void LowShelfBase::setup (int order,
double sampleRate,
double cutoffFrequency,
double gainDb,
double stopBandDb)
{
m_analogProto.design (order, gainDb, stopBandDb);

LowPassTransform (cutoffFrequency / sampleRate,
m_digitalProto,
m_analogProto);

Cascade::setLayout (m_digitalProto);
}

void HighShelfBase::setup (int order,
double sampleRate,
double cutoffFrequency,
double gainDb,
double stopBandDb)
{
m_analogProto.design (order, gainDb, stopBandDb);

HighPassTransform (cutoffFrequency / sampleRate,
m_digitalProto,
m_analogProto);

Cascade::setLayout (m_digitalProto);
}

void BandShelfBase::setup (int order,
double sampleRate,
double centerFrequency,
double widthFrequency,
double gainDb,
double stopBandDb)
{
m_analogProto.design (order, gainDb, stopBandDb);

BandPassTransform (centerFrequency / sampleRate,
widthFrequency / sampleRate,
m_digitalProto,
m_analogProto);

m_digitalProto.setNormal (((centerFrequency/sampleRate) < 0.25) ? doublePi : 0, 1);

Cascade::setLayout (m_digitalProto);
}

}

}

+ 66
- 0
ports-juce6/roth-air/DspFilters/source/Custom.cpp View File

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

"A Collection of Useful C++ Classes for Digital Signal Processing"
By Vincent Falco

Official project location:
http://code.google.com/p/dspfilterscpp/

See Documentation.cpp for contact information, notes, and bibliography.

--------------------------------------------------------------------------------

License: MIT License (http://www.opensource.org/licenses/mit-license.php)
Copyright (c) 2009 by Vincent Falco

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 "DspFilters/Common.h"
#include "DspFilters/Custom.h"

namespace Dsp {

namespace Custom {

void OnePole::setup (double scale,
double pole,
double zero)
{
setOnePole (pole, zero);
applyScale (scale);
}

void TwoPole::setup (double scale,
double poleRho,
double poleTheta,
double zeroRho,
double zeroTheta)
{
complex_t pole = std::polar (poleRho, poleTheta);
complex_t zero = std::polar (zeroRho, zeroTheta);

setTwoPole (pole, zero, std::conj(pole), std::conj(zero));
applyScale (scale);
}

}

}

+ 41
- 0
ports-juce6/roth-air/DspFilters/source/Design.cpp View File

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

"A Collection of Useful C++ Classes for Digital Signal Processing"
By Vincent Falco

Official project location:
http://code.google.com/p/dspfilterscpp/

See Documentation.cpp for contact information, notes, and bibliography.

--------------------------------------------------------------------------------

License: MIT License (http://www.opensource.org/licenses/mit-license.php)
Copyright (c) 2009 by Vincent Falco

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 "DspFilters/Common.h"
#include "DspFilters/Design.h"

namespace Dsp {

}

+ 456
- 0
ports-juce6/roth-air/DspFilters/source/Documentation.cpp View File

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

"A Collection of Useful C++ Classes for Digital Signal Processing"
By Vincent Falco

Official project location:
http://code.google.com/p/dspfilterscpp/

See Documentation.h for contact information, notes, and bibliography.

--------------------------------------------------------------------------------

License: MIT License (http://www.opensource.org/licenses/mit-license.php)
Copyright (c) 2009 by Vincent Falco

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.

********************************************************************************

="A Collection of Useful C++ Classes for Digital Signal Processing"=
_By Vincent Falco_

_"Techniques for digital signal processing are well guarded and held
close to the chest, as they have valuable applications for multimedia
content. The black art of Infinite Impulse Response ("IIR") filtering
has remained shrouded in secrecy with little publicly available source
code....until now."_

----
Building on the work of cherished luminaries such as Sophocles Orfanidis, Andreas Antoniou, Martin Holters, and Udo Zolzer, this library harnesses the power of C++ templates to solve a useful problem in digital signal processing: the realization of multichannel IIR filters of arbitrary order and prescribed specifications with various properties such as Butterworth, Chebyshev, Elliptic, and Optimum-L (Legendre) responses. The library is provided under the MIT license and is therefore fully compatible with proprietary usage.

Classes are designed as independent re-usable building blocks. Use some or all of the provided features, or extend the functionality by writing your own objects that plug into the robust framework. Only the code that you need will get linked into your application. Here's a list of features:

* Exclusive focus on IIR filters instead of boring FIR filters
* Complete implementation of all "RBJ Biquad" Cookbook filter formulas
* Butterworth, Chebyshev, Elliptic, Bessel, Legendre designs
* Low Pass, High Pass, Band Pass, Band Stop transformations
* Low, High, and Band Shelf filter implementations for most types
* Smooth interpolation of filter settings, pole/zeros, and biquad coefficients to achieve seamless parameter changes
* Representation of digital filters using poles and zeros
* Realization using Direct Form I, Direct Form II, or user provided class
* Fully factored to minimize template instantiations
* "Design" layer provides runtime introspection into a filter
* Utility template functions for manipulating buffers of sample data
* No calls to malloc or new, great for embedded systems
* No external dependencies, just the standard C++ library!

Using these filters is easy:

{{{
// Create a Chebyshev type I Band Stop filter of order 3
// with state for processing 2 channels of audio.
Dsp::SimpleFilter <Dsp::ChebyshevI::BandStop <3>, 2> f;
f.setup (3, // order
44100,// sample rate
4000, // center frequency
880, // band width
1); // ripple dB
f.process (numSamples, arrayOfChannels);
}}}

An accompanying demonstration program that works on most popular platforms by using the separately licensed Juce application framework (included), exercises all the functionality of the library, including these features:

* Dynamic interface creates itself using filter introspection capabilities
* Audio playback with real time application of a selected filter
* Live time stretching and amplitude modulation without clicks or popping
* Charts to show magnitude, phase response and pole/zero placement
* Thread safety "best practices" for audio applications

Here's a screenshot of the DspFilters Demo

http://dspfilterscpp.googlecode.com/files/dspfiltersdemo.png

If you've been searching in futility on the Internet for some source code for implementing high order filters, then look no further because this is it! Whether you are a student of C++ or digital signal processing, a writer of audio plugins, or even a VST synthesizer coder, "A Collection of Useful C++ Classes for Digital Signal Processing" might have something for you!

********************************************************************************

Notes:

Please direct all comments this DSP and Plug-in Development forum:

http://www.kvraudio.com/forum/viewforum.php?f=33

Credits

All of this code was written by the author Vincent Falco except where marked.

Some filter ideas are based on a java applet (http://www.falstad.com/dfilter/)
developed by Paul Falstad.

Bibliography

"High-Order Digital Parametric Equalizer Design"
Sophocles J. Orfanidis
(Journal of the Audio Engineering Society, vol 53. pp 1026-1046)

http://crca.ucsd.edu/~msp/techniques/v0.08/book-html/node1.html
"Spectral Transformations for digital filters"
A. G. Constantinides, B.Sc.(Eng.) Ph.D.
(Proceedings of the IEEE, vol. 117, pp. 1585-1590, August 1970)

********************************************************************************

DOCUMENTATION

All symbols are in the Dsp namespace.

class Filter

This is an abstract polymorphic interface that supports any filter. The
parameters to the filter are passed in the Params structure, which is
essentially an array of floating point numbers with a hard coded size
limit (maxParameters). Each filter makes use of the Params as it sees fit.

Filter::getKind ()
Filter::getName ()
Filter::getNumParams ()
Filter::getParamInfo ()

Through the use of these functions, the caller can determine the meaning
of each indexed filter parameter at run-time. The ParamInfo structure
contains methods that describe information about an individual parameter,
including convenience functions to map a filter parameter to a "control
value" in the range 0...1, suitable for presentation by a GUI element such
as a knob or scrollbar.

Filter::getDefaultParams ()
Filter::getParams ()
Filter::getParam ()
Filter::setParam ()
Filter::findParamId ()
Filter::setParamById ()
Filter::setParams ()
Filter::copyParamsFrom ()

These methods allow the caller to inspect the values of the parameters,
and set the filter parameters in various ways. When parameters are changed
they take effect on the filter immediately.

Filter::getPoleZeros ()
Filter::response ()

For analysis, these routines provide insight into the pole/zero arrangement
in the z-plane, and the complex valued response at a given normalized
frequency in the range (0..nyquist = 0.5]. From the complex number the
magnitude and phase can be calculated.

Filter::getNumChannels()
Filter::reset()
Filter::process()

These functions are for applying the filter to channels of data. If the
filter was not created with channel state (i.e. Channels==0 in the derived
class template) then they will throw an exception.

To create a Filter object, use operator new on a subclass template with
appropriate parameters based on the type of filter you want. Here are the
subclasses.



template <class DesignClass, int Channels = 0, class StateType = DirectFormII>
class FilterDesign : public Filter

This subclass of Filter takes a DesignClass (explained below) representing
a filter, an optional parameter for the number of channels of data to
process, and an optional customizable choice of which state realization
to use for processing samples. Channels may be zero, in which case the
object can only be used for analysis.

Because the DesignClass is a member and not inherited, it is in general
not possible to call members of the DesignClass directly. You must go
through the Filter interface.



template <class DesignClass, int Channels, class StateType = DirectFormII>
class SmoothedFilterDesign : public Filter

This subclass of FilterDesign implements a filter of the given DesignClass,
and also performs smoothing of parameters over time. Specifically, when
one or more filter parameters (such as cutoff frequency) are changed, the
class creates a transition over a given number of samples from the original
values to the new values. This process is invisible and seamless to the
caller, except that the constructor takes an additional parameter that
indicates the duration of transitions when parameters change.



template <class FilterClass, int Channels = 0, class StateType = DirectFormII>
class SimpleFilter : public FilterClass

This is a simple wrapper around a given raw FilterClass (explained below).
It uses inheritance so all of the members of the FilterClass are available
to instances of this object. The simple wrapper provides state information
for processing channels in the given form.

The wrapper does not support introspection, parameter smoothing, or the
Params style of applying filter settings. Instead, it uses the interface
of the given FilterClass, which is typically a function called setup()
that takes a list of arguments representing the parameters.

The use of this class bypasses the virtual function overhead of going
through a Filter object. It is not practical to change filter parameters
of a SimpleFilter, unless you are re-using the filter for a brand new
stream of data in which case reset() should be called immediately before
or after changing parameters, to clear the state and prevent audible
artifacts.



Filter family namespaces

Each family of filters is given its own namespace. Currently these namespaces
include:

RBJ: Filters from the RBJ Cookbook
Butterworth: Filters with Butterworth response
ChebyshevI: Filters using Chebyshev polynomials (ripple in the passband)
ChebyshevII: "Inverse Chebyshev" filters (ripple in the stopband)
Elliptic: Filters with ripple in both the passband and stopband
Bessel: Uses Bessel polynomials, theoretically with linear phase
Legendre: "Optimum-L" filters with steepest transition and monotonic passband.
Custom: Simple filters that allow poles and zeros to be specified directly

<class FilterClass>

Within each namespace we have a set of "raw filters" (each one is an example
of a FilterClass). For example, the raw filters in the Butterworth namespace are:

Butterworth::LowPass
Butterworth::HighPass
Butterworth::BandPass
Butterworth::BandStop
Butterworth::LowShelf
Butterworth::HighShelf
Butterworth::BandShelf

When a class template (such as SimpleFilter) requires a FilterClass, it is
expecting an identifier of a raw filter. For example, Legendre::LowPass. The
raw filters do not have any support for introspection or the Params style of
changing filter settings. All they offer is a setup() function for updating
the IIR coefficients to a given set of parameters.

<class DesignClass>

Each filter family namespace also has the nested namespace "Design". Inside
this namespace we have all of the raw filter names repeated, except that
these classes additional provide the Design interface, which adds
introspection, polymorphism, the Params style of changing filter settings,
and in general all of the features necessary to interoperate with the Filter
virtual base class and its derived classes. For example, the design filters
from the Butterworth namespace are:

Butterworth::Design::LowPass
Butterworth::Design::HighPass
Butterworth::Design::BandPass
Butterworth::Design::BandStop
Butterworth::Design::LowShelf
Butterworth::Design::HighShelf
Butterworth::Design::BandShelf

For any class template that expects a DesignClass, you must pass a suitable
object from the Design namespace of the desired filter family. For example,
ChebyshevI::Design::BandPass.

*******************************************************************************/

//
// Usage Examples
//
// This shows you how to operate the filters
//

// This is the only include you need
#include "DspFilters/Dsp.h"

#include <sstream>
#include <iostream>
#include <iomanip>

namespace {

void UsageExamples ()
{
// create a two channel audio buffer
int numSamples = 2000;
float* audioData[2];
audioData[0] = new float[numSamples];
audioData[1] = new float[numSamples];

// create a 2-channel RBJ Low Pass with parameter smoothing
// and apply it to the audio data
{
// "1024" is the number of samples over which to fade parameter changes
Dsp::Filter* f = new Dsp::SmoothedFilterDesign
<Dsp::RBJ::Design::LowPass, 2> (1024);
Dsp::Params params;
params[0] = 44100; // sample rate
params[1] = 4000; // cutoff frequency
params[2] = 1.25; // Q
f->setParams (params);
f->process (numSamples, audioData);
}
// set up a 2-channel RBJ High Pass with parameter smoothing,
// but bypass virtual function overhead
{
// the difference here is that we don't go through a pointer.
Dsp::SmoothedFilterDesign <Dsp::RBJ::Design::LowPass, 2> f (1024);
Dsp::Params params;
params[0] = 44100; // sample rate
params[1] = 4000; // cutoff frequency
params[2] = 1.25; // Q
f.setParams (params);
f.process (numSamples, audioData);
}

// create a 2-channel Butterworth Band Pass of order 4,
// with parameter smoothing and apply it to the audio data.
// Output samples are generated using Direct Form II realization.
{
Dsp::Filter* f = new Dsp::SmoothedFilterDesign
<Dsp::Butterworth::Design::BandPass <4>, 2, Dsp::DirectFormII> (1024);
Dsp::Params params;
params[0] = 44100; // sample rate
params[1] = 4; // order
params[2] = 4000; // center frequency
params[3] = 880; // band width
f->setParams (params);
f->process (numSamples, audioData);
}
// create a 2-channel Inverse Chebyshev Low Shelf of order 5
// and passband ripple 0.1dB, without parameter smoothing and apply it.
{
Dsp::Filter* f = new Dsp::FilterDesign
<Dsp::ChebyshevII::Design::LowShelf <5>, 2>;
Dsp::Params params;
params[0] = 44100; // sample rate
params[1] = 5; // order
params[2] = 4000; // corner frequency
params[3] = 6; // shelf gain
params[4] = 0.1; // passband ripple
f->setParams (params);
f->process (numSamples, audioData);
}
// create an abstract Butterworth High Pass of order 4.
// This one can't process channels, it can only be used for analysis
// (i.e. extract poles and zeros).
{
Dsp::Filter* f = new Dsp::FilterDesign
<Dsp::Butterworth::Design::HighPass <4> >;
Dsp::Params params;
params[0] = 44100; // sample rate
params[1] = 4; // order
params[2] = 4000; // cutoff frequency
f->setParams (params);
// this will cause a runtime assertion
f->process (numSamples, audioData);
}

// Use the simple filter API to create a Chebyshev Band Stop of order 3
// and 1dB ripple in the passband. The simle API has a smaller
// footprint, but no introspection or smoothing.
{
// Note we use the raw filter instead of the one
// from the Design namespace.
Dsp::SimpleFilter <Dsp::ChebyshevI::BandStop <3>, 2> f;
f.setup (3, // order
44100,// sample rate
4000, // center frequency
880, // band width
1); // ripple dB
f.process (numSamples, audioData);
}

// Set up a filter, extract the coefficients and print them to standard
// output. Note that this filter is not capable of processing samples,
// as it has no state. It only has coefficients.
{
Dsp::SimpleFilter <Dsp::RBJ::LowPass> f;
f.setup (44100, // sample rate Hz
440, // cutoff frequency Hz
1); // "Q" (resonance)

std::ostringstream os;

os << "a0 = " << f.getA0 () << "\n"
<< "a1 = " << f.getA1 () << "\n"
<< "a2 = " << f.getA2 () << "\n"
<< "b0 = " << f.getB0 () << "\n"
<< "b1 = " << f.getB1 () << "\n"
<< "b2 = " << f.getB2 () << "\n";
;

std::cout << os.str();
}

// Create an instance of a raw filter. This is as low as it gets, any
// lower and we will just have either a Biquad or a Cascade, and you'll
// be setting the coefficients manually.
{
// This is basically like eating uncooked food
Dsp::RBJ::LowPass f;
f.setup (44100, 440, 1);

// calculate response at frequency 440 Hz
Dsp::complex_t response = f.response (440./44100);
}

// Extract coefficients from a Cascade
{
Dsp::SimpleFilter <Dsp::Butterworth::HighPass <3> > f;
f.setup (3, 44100, 2000);

std::ostringstream os;

os << "numStages = " << f.getNumStages() << "\n"
<< "a0[0] = " << f[0].getA0 () << "\n"
<< "a1[0] = " << f[0].getA1 () << "\n"
<< "a2[0] = " << f[0].getA2 () << "\n"
<< "b0[0] = " << f[0].getB0 () << "\n"
<< "b1[0] = " << f[0].getB1 () << "\n"
<< "b2[0] = " << f[0].getB2 () << "\n"
<< "a0[1] = " << f[1].getA0 () << "\n"
<< "a1[1] = " << f[1].getA1 () << "\n"
<< "a2[1] = " << f[1].getA2 () << "\n"
<< "b0[1] = " << f[1].getB0 () << "\n"
<< "b1[1] = " << f[1].getB1 () << "\n"
<< "b2[1] = " << f[1].getB2 () << "\n"
;

std::cout << os.str();
}
}

}

+ 384
- 0
ports-juce6/roth-air/DspFilters/source/Elliptic.cpp View File

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

"A Collection of Useful C++ Classes for Digital Signal Processing"
By Vincent Falco

Official project location:
http://code.google.com/p/dspfilterscpp/

See Documentation.cpp for contact information, notes, and bibliography.

--------------------------------------------------------------------------------

License: MIT License (http://www.opensource.org/licenses/mit-license.php)
Copyright (c) 2009 by Vincent Falco

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 "DspFilters/Common.h"
#include "DspFilters/Elliptic.h"

namespace Dsp {

namespace Elliptic {

// shit ton of math in here

// approximation to complete elliptic integral of the first kind.
// fast convergence, peak error less than 2e-16.
double Solver::ellipticK (double k)
{
double m = k*k;
double a = 1;
double b = sqrt (1 - m);
double c = a - b;
double co;
do
{
co = c;
c = (a - b) / 2;
double ao = (a + b) / 2;
b = sqrt (a*b);
a = ao;
}
while (c<co);
return doublePi / (a + a);
}

//------------------------------------------------------------------------------

AnalogLowPass::AnalogLowPass ()
: m_numPoles (-1)
{
setNormal (0, 1);
}

void AnalogLowPass::design (int numPoles,
double rippleDb,
double rolloff)
{
if (m_numPoles != numPoles ||
m_rippleDb != rippleDb ||
m_rolloff != rolloff)
{
m_numPoles = numPoles;
m_rippleDb = rippleDb;
m_rolloff = rolloff;

reset ();

// calculate
//const double ep = rippleDb; // passband ripple

const int n = numPoles;

double e2=pow(10.,rippleDb/10)-1;
//double xi = rolloff + 1;
double xi = 5 * exp (rolloff - 1) + 1;

m_K = Solver::ellipticK(1/xi);
m_Kprime = Solver::ellipticK(sqrt(1-1/(xi*xi)));

int ni = ((n & 1) == 1) ? 0 : 1;
int i;
double f[100]; // HACK!!!
for (i = 1; i <= n/2; i++)
{
double u = (2*i-ni)*m_K/n;
double sn = calcsn(u);
sn *= 2*doublePi/m_K;
f[i] = m_zeros[i-1] = 1/sn;
}
m_zeros[n/2] = std::numeric_limits<double>::infinity();
double fb = 1/(2*doublePi);
m_nin = n % 2;
m_n2 = n/2;
for (i = 1; i <= m_n2; i++)
{
double x = f[m_n2+1-i];
m_z1[i] = sqrt(1-1/(x*x));
}
double ee = e2;//pow(10., rippleDb/20)-1;
m_e = sqrt(ee);
double fbb = fb*fb;
m_m = m_nin+2*m_n2;
m_em = 2*(m_m/2);
double tp = 2*doublePi;
calcfz();
calcqz();
if (m_m > m_em)
m_c1[2*m_m] = 0;
for (i = 0; i <= 2*m_m; i += 2)
m_a1[m_m-i/2] = m_c1[i] + m_d1[i];
double a0 = findfact(m_m);
int r = 0;
while (r < m_em/2)
{
r++;
m_p[r] /= 10;
m_q1[r] /= 100;
double d = 1+m_p[r]+m_q1[r];
m_b1[r] = (1+m_p[r]/2)*fbb/d;
m_zf1[r] = fb/pow(d, .25);
m_zq1[r] = 1/sqrt(abs(2*(1-m_b1[r]/(m_zf1[r]*m_zf1[r]))));
m_zw1[r] = tp*m_zf1[r];

m_rootR[r] = -.5*m_zw1[r]/m_zq1[r];
m_rootR[r+m_em/2] = m_rootR[r];
m_rootI[r] = .5*sqrt(abs(m_zw1[r]*m_zw1[r]/(m_zq1[r]*m_zq1[r]) - 4*m_zw1[r]*m_zw1[r]));
m_rootI[r+m_em/2] = -m_rootI[r];

complex_t pole (
-.5*m_zw1[r]/m_zq1[r],
.5*sqrt(abs(m_zw1[r]*m_zw1[r]/(m_zq1[r]*m_zq1[r]) - 4*m_zw1[r]*m_zw1[r])));

complex_t zero (0, m_zeros[r-1]);

addPoleZeroConjugatePairs (pole, zero);
}

if (a0 != 0)
{
m_rootR[r+1+m_em/2] = -sqrt(fbb/(.1*a0-1))*tp;
m_rootI[r+1+m_em/2] = 0;

add (-sqrt(fbb/(.1*a0-1))*tp, infinity());
}

setNormal (0, (numPoles&1) ? 1. : pow (10., -rippleDb / 20.0));
}
}

// generate the product of (z+s1[i]) for i = 1 .. sn and store it in b1[]
// (i.e. f[z] = b1[0] + b1[1] z + b1[2] z^2 + ... b1[sn] z^sn)
void AnalogLowPass::prodpoly( int sn )
{
m_b1[0] = m_s1[1];
m_b1[1] = 1;
int i, j;
for (j = 2; j <= sn; j++)
{
m_a1[0] = m_s1[j]*m_b1[0];
for (i = 1; i <= j-1; i++)
m_a1[i] = m_b1[i-1]+m_s1[j]*m_b1[i];
for (i = 0; i != j; i++)
m_b1[i] = m_a1[i];
m_b1[j] = 1;
}
}

// determine f(z)^2
void AnalogLowPass::calcfz2( int i )
{
int ji = 0;
int jf = 0;
if (i < m_em+2)
{
ji = 0;
jf = i;
}
if (i > m_em)
{
ji = i-m_em;
jf = m_em;
}
m_c1[i] = 0;
int j;
for(j = ji; j <= jf; j += 2)
m_c1[i] += m_a1[j]*(m_a1[i-j]*pow(10., m_m-i/2));
}

// calculate f(z)
void AnalogLowPass::calcfz( void )
{
int i = 1;
if( m_nin == 1 )
m_s1[i++] = 1;
for (; i <= m_nin+m_n2; i++)
m_s1[i] = m_s1[i+m_n2] = m_z1[i-m_nin];
prodpoly(m_nin+2*m_n2);
for (i = 0; i <= m_em; i += 2)
m_a1[i] = m_e*m_b1[i];
for (i = 0; i <= 2*m_em; i += 2)
calcfz2(i);
}

// determine q(z)
void AnalogLowPass::calcqz( void )
{
int i;
for (i = 1; i <= m_nin; i++)
m_s1[i] = -10;
for (; i <= m_nin+m_n2; i++)
m_s1[i] = -10*m_z1[i-m_nin]*m_z1[i-m_nin];
for (; i <= m_nin+2*m_n2; i++)
m_s1[i] = m_s1[i-m_n2];
prodpoly(m_m);
int dd = ((m_nin & 1) == 1) ? -1 : 1;
for (i = 0; i <= 2*m_m; i += 2)
m_d1[i] = dd*m_b1[i/2];
}

// compute factors
double AnalogLowPass::findfact(int t)
{
int i;
double a = 0;
for (i = 1; i <= t; i++)
m_a1[i] /= m_a1[0];
m_a1[0] = m_b1[0] = m_c1[0] = 1;
int i1 = 0;
for(;;)
{
if (t <= 2)
break;
double p0 = 0, q0 = 0;
i1++;
for(;;)
{
m_b1[1] = m_a1[1] - p0;
m_c1[1] = m_b1[1] - p0;
for (i = 2; i <= t; i++)
m_b1[i] = m_a1[i]-p0*m_b1[i-1]-q0*m_b1[i-2];
for (i = 2; i < t; i++)
m_c1[i] = m_b1[i]-p0*m_c1[i-1]-q0*m_c1[i-2];
int x1 = t-1;
int x2 = t-2;
int x3 = t-3;
double x4 = m_c1[x2]*m_c1[x2]+m_c1[x3]*(m_b1[x1]-m_c1[x1]);
if (x4 == 0)
x4 = 1e-3;
double ddp = (m_b1[x1]*m_c1[x2]-m_b1[t]*m_c1[x3])/x4;
p0 += ddp;
double dq = (m_b1[t]*m_c1[x2]-m_b1[x1]*(m_c1[x1]-m_b1[x1]))/x4;
q0 += dq;
if (abs(ddp+dq) < 1e-6)
break;
}
m_p[i1] = p0;
m_q1[i1] = q0;
m_a1[1] = m_a1[1]-p0;
t -= 2;
for (i = 2; i <= t; i++)
m_a1[i] -= p0*m_a1[i-1]+q0*m_a1[i-2];
if (t <= 2)
break;
}

if (t == 2)
{
i1++;
m_p[i1] = m_a1[1];
m_q1[i1] = m_a1[2];
}
if (t == 1)
a = -m_a1[1];

return a;
}

double AnalogLowPass::calcsn(double u)
{
double sn = 0;
int j;
// q = modular constant
double q = exp(-doublePi*m_Kprime/m_K);
double v = doublePi*.5*u/m_K;
for (j = 0; ; j++)
{
double w = pow(q, j+.5);
sn += w*sin((2*j+1)*v)/(1-w*w);
if (w < 1e-7)
break;
}
return sn;
}

//------------------------------------------------------------------------------

void LowPassBase::setup (int order,
double sampleRate,
double cutoffFrequency,
double rippleDb,
double rolloff)
{
m_analogProto.design (order, rippleDb, rolloff);

LowPassTransform (cutoffFrequency / sampleRate,
m_digitalProto,
m_analogProto);

Cascade::setLayout (m_digitalProto);
}

void HighPassBase::setup (int order,
double sampleRate,
double cutoffFrequency,
double rippleDb,
double rolloff)
{
m_analogProto.design (order, rippleDb, rolloff);

HighPassTransform (cutoffFrequency / sampleRate,
m_digitalProto,
m_analogProto);

Cascade::setLayout (m_digitalProto);
}

void BandPassBase::setup (int order,
double sampleRate,
double centerFrequency,
double widthFrequency,
double rippleDb,
double rolloff)
{
m_analogProto.design (order, rippleDb, rolloff);

BandPassTransform (centerFrequency / sampleRate,
widthFrequency / sampleRate,
m_digitalProto,
m_analogProto);

Cascade::setLayout (m_digitalProto);
}

void BandStopBase::setup (int order,
double sampleRate,
double centerFrequency,
double widthFrequency,
double rippleDb,
double rolloff)
{
m_analogProto.design (order, rippleDb, rolloff);

BandStopTransform (centerFrequency / sampleRate,
widthFrequency / sampleRate,
m_digitalProto,
m_analogProto);

Cascade::setLayout (m_digitalProto);
}

}

}

+ 117
- 0
ports-juce6/roth-air/DspFilters/source/Filter.cpp View File

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

"A Collection of Useful C++ Classes for Digital Signal Processing"
By Vincent Falco

Official project location:
http://code.google.com/p/dspfilterscpp/

See Documentation.cpp for contact information, notes, and bibliography.

--------------------------------------------------------------------------------

License: MIT License (http://www.opensource.org/licenses/mit-license.php)
Copyright (c) 2009 by Vincent Falco

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 "DspFilters/Common.h"
#include "DspFilters/Filter.h"

namespace Dsp {

Params Filter::getDefaultParams() const
{
Params params;

params.clear();

for (int i = 0; i < getNumParams(); ++i)
params[i] = getParamInfo(i).getDefaultValue();

return params;
}

Filter::~Filter()
{
}

int Filter::findParamId (int paramId)
{
int index = -1;

for (int i = getNumParams(); --i >= 0;)
{
if (getParamInfo (i).getId () == paramId)
{
index = i;
break;
}
}

return index;
}

void Filter::setParamById (int paramId, double nativeValue)
{
for (int i = getNumParams(); --i >= 0;)
{
if (getParamInfo (i).getId () == paramId)
{
setParam (i, nativeValue);
return;
}
}
assert (0);
}

void Filter::copyParamsFrom (Dsp::Filter const* other)
{
// first, set reasonable defaults
m_params = getDefaultParams ();

if (other)
{
// now loop
for (int i = 0; i < getNumParams (); ++i)
{
const ParamInfo& paramInfo = getParamInfo (i);

// find a match
for (int j = 0; j < other->getNumParams(); ++j)
{
const ParamInfo& otherParamInfo = other->getParamInfo (j);

if (paramInfo.getId() == otherParamInfo.getId())
{
// match!
m_params [i] = paramInfo.clamp (other->getParam (j));
break;
}
}
}
}

doSetParams (m_params);
}

}

+ 344
- 0
ports-juce6/roth-air/DspFilters/source/Legendre.cpp View File

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

"A Collection of Useful C++ Classes for Digital Signal Processing"
By Vincent Falco

Official project location:
http://code.google.com/p/dspfilterscpp/

See Documentation.cpp for contact information, notes, and bibliography.

--------------------------------------------------------------------------------

License: MIT License (http://www.opensource.org/licenses/mit-license.php)
Copyright (c) 2009 by Vincent Falco

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 "DspFilters/Common.h"
#include "DspFilters/Legendre.h"
#include "DspFilters/RootFinder.h"

#include <sstream>
#include <iostream>
#include <iomanip>

namespace Dsp {

namespace Legendre {

static inline double m_sqrt2 ()
{
return 1.41421356237309504880;
}

// Optimum 'L' Filter algorithm.
// (C) 2004, C. Bond.
//
// Based on discussion in Kuo, "Network Analysis and Synthesis",
// pp. 379-383. Original method due to A.Papoulis."On Monotonic
// Response Filters", Proc. IRE, 47, Feb. 1959.
//
// Rewritten by Vincent Falco to change the way temporary
// storage is allocated
//

//
// This routine calculates the coefficients of the Legendre polynomial
// of the 1st kind. It uses a recursion relation. The first few polynomials
// are hard coded and the rest are found by recursion.
//
// (n+1)Pn+1 = (2n+1)xPn - nPn-1 Recursion relation.
//
void PolynomialFinderBase::legendre (double *p, int n)
{
int i,j;

if (n == 0) {
p[0] = 1.0;
return;
}
if (n == 1) {
p[0] = 0.0;
p[1] = 1.0;
return;
}
p[0] = -0.5;
p[1] = 0.0;
p[2] = 1.5;

if (n == 2) return;

for (i=0;i<=n;i++) {
m_aa[i] = m_bb[i] = 0.0;
}
m_bb[1] = 1.0;

for (i=3;i<=n;i++) {
for (j=0;j<=i;j++) {
m_aa[j] = m_bb[j];
m_bb[j] = p[j];
p[j] = 0.0;
}
for (j=i-2;j>=0;j-=2) {
p[j] -= (i-1)*m_aa[j]/i;
}
for (j=i-1;j>=0;j-=2) {
p[j+1] += (2*i-1)*m_bb[j]/i;
}
}
}

//
//
// In the following routine n = 2k + 1 for odd 'n' and n = 2k + 2 for
// even 'n'.
//
//
// n k
// -----
// 1 0
// 2 0
// 3 1
// 4 1
// 5 2
// 6 2
//

void PolynomialFinderBase::solve (int n)
{
assert (n <= m_maxN);

double c0,c1;
int i,j,k;

k = (n-1)/2;
//
// form vector of 'a' constants
//
if (n & 1) { // odd
for (i=0;i<=k;i++) {
m_a[i] = (2.0*i+1.0)/(m_sqrt2()*(k+1.0));
}
} // even
else {
for (i=0;i<k+1;i++) {
m_a[i] = 0.0;
}
if (k & 1) {
for (i=1;i<=k;i+=2) {
m_a[i] = (2*i+1)/sqrt(double((k+1)*(k+2)));
}
}
else {
for (i=0;i<=k;i+=2) {
m_a[i] = (2*i+1)/sqrt(double((k+1)*(k+2)));
}
}
}
for (i=0;i<=n;i++){
m_s[i] = 0.0;
m_w[i] = 0.0;
}
//
// form s[] = sum of a[i]*P[i]
//
m_s[0] = m_a[0];
m_s[1] = m_a[1];
for (i=2;i<=k;i++) {
legendre(m_p,i);
for (j=0;j<=i;j++) {
m_s[j] += m_a[i]*m_p[j];
}
}
//
// form v[] = square of s[]
//
for (i=0;i<=2*k+2;i++) {
m_v[i] = 0.0;
}
for (i=0;i<=k;i++) {
for (j=0;j<=k;j++) {
m_v[i+j] += m_s[i]*m_s[j];
}
}
//
// modify integrand for even 'n'
//
m_v[2*k+1] = 0.0;
if ((n & 1) == 0) {
for (i=n;i>=0;i--) {
m_v[i+1] += m_v[i];
}
}
//
// form integral of v[]
//
for (i=n+1;i>=0;i--) {
m_v[i+1] = m_v[i]/(double)(i+1.0);
}
m_v[0] = 0.0;
//
// clear s[] for use in computing definite integral
//
for (i=0;i<(n+2);i++){
m_s[i] = 0.0;
}
m_s[0] = -1.0;
m_s[1] = 2.0;
//
// calculate definite integral
//
for (i=1;i<=n;i++) {
if (i > 1) {
c0 = -m_s[0];
for (j=1;j<i+1;j++) {
c1 = -m_s[j] + 2.0*m_s[j-1];
m_s[j-1] = c0;
c0 = c1;
}
c1 = 2.0*m_s[i];
m_s[i] = c0;
m_s[i+1] = c1;
}
for (j=i;j>0;j--) {
m_w[j] += (m_v[i]*m_s[j]);
}
}
if ((n & 1) == 0) m_w[1] = 0.0;
}

//------------------------------------------------------------------------------

AnalogLowPass::AnalogLowPass ()
: m_numPoles (-1)
{
setNormal (0, 1);
}

void AnalogLowPass::design (int numPoles,
WorkspaceBase* w)
{
if (m_numPoles != numPoles)
{
m_numPoles = numPoles;

reset ();

PolynomialFinderBase& poly (w->poly);
RootFinderBase& poles (w->roots);

poly.solve (numPoles);
int degree = numPoles * 2;

poles.coef()[0] = 1 + poly.coef()[0];
poles.coef()[1] = 0;
for (int i = 1; i <= degree; ++i)
{
poles.coef()[2*i] = poly.coef()[i] * ((i & 1) ? -1 : 1);
poles.coef()[2*i+1] = 0;
}
poles.solve (degree);

int j = 0;
for (int i = 0; i < degree; ++i)
if (poles.root()[i].real() <= 0)
poles.root()[j++] = poles.root()[i];
// sort descending imag() and cut degree in half
poles.sort (degree/2);

const int pairs = numPoles / 2;
for (int i = 0; i < pairs; ++i)
{
complex_t c = poles.root()[i];
addPoleZeroConjugatePairs (c, infinity());
}

if (numPoles & 1)
add (poles.root()[pairs].real(), infinity());
}
}

//------------------------------------------------------------------------------

void LowPassBase::setup (int order,
double sampleRate,
double cutoffFrequency,
WorkspaceBase* w)
{
m_analogProto.design (order, w);

LowPassTransform (cutoffFrequency / sampleRate,
m_digitalProto,
m_analogProto);

Cascade::setLayout (m_digitalProto);
}

void HighPassBase::setup (int order,
double sampleRate,
double cutoffFrequency,
WorkspaceBase* w)
{
m_analogProto.design (order, w);

HighPassTransform (cutoffFrequency / sampleRate,
m_digitalProto,
m_analogProto);

Cascade::setLayout (m_digitalProto);
}

void BandPassBase::setup (int order,
double sampleRate,
double centerFrequency,
double widthFrequency,
WorkspaceBase* w)
{
m_analogProto.design (order, w);

BandPassTransform (centerFrequency / sampleRate,
widthFrequency / sampleRate,
m_digitalProto,
m_analogProto);

Cascade::setLayout (m_digitalProto);
}

void BandStopBase::setup (int order,
double sampleRate,
double centerFrequency,
double widthFrequency,
WorkspaceBase* w)
{
m_analogProto.design (order, w);

BandStopTransform (centerFrequency / sampleRate,
widthFrequency / sampleRate,
m_digitalProto,
m_analogProto);

Cascade::setLayout (m_digitalProto);
}

}

}

+ 309
- 0
ports-juce6/roth-air/DspFilters/source/Param.cpp View File

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

"A Collection of Useful C++ Classes for Digital Signal Processing"
By Vincent Falco

Official project location:
http://code.google.com/p/dspfilterscpp/

See Documentation.cpp for contact information, notes, and bibliography.

--------------------------------------------------------------------------------

License: MIT License (http://www.opensource.org/licenses/mit-license.php)
Copyright (c) 2009 by Vincent Falco

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 "DspFilters/Common.h"
#include "DspFilters/Design.h"

#include <stdexcept>
#include <sstream>
#include <iostream>
#include <iomanip>

namespace Dsp {

ParamInfo::ParamInfo ()
{
throw std::logic_error ("invalid usage of ParamInfo");
}

double ParamInfo::clamp (double nativeValue) const
{
const double minValue = toNativeValue (0);
const double maxValue = toNativeValue (1);
if (nativeValue < minValue)
nativeValue = minValue;
else if (nativeValue > maxValue)
nativeValue = maxValue;
return nativeValue;
}

//------------------------------------------------------------------------------

double ParamInfo::Int_toControlValue (double nativeValue) const
{
return (nativeValue - m_arg1) / (m_arg2 - m_arg1);
}

double ParamInfo::Int_toNativeValue (double controlValue) const
{
return std::floor (m_arg1 + controlValue * (m_arg2 - m_arg1) + 0.5);
}

//------------------------------------------------------------------------------

double ParamInfo::Real_toControlValue (double nativeValue) const
{
return (nativeValue - m_arg1) / (m_arg2 - m_arg1);
}

double ParamInfo::Real_toNativeValue (double controlValue) const
{
return m_arg1 + controlValue * (m_arg2 - m_arg1);
}

//------------------------------------------------------------------------------

double ParamInfo::Log_toControlValue (double nativeValue) const
{
const double base = 1.5;
double l0 = log (m_arg1) / log (base);
double l1 = log (m_arg2) / log (base);
return (log (nativeValue) / log(base) - l0) / (l1 - l0);
}

double ParamInfo::Log_toNativeValue (double controlValue) const
{
const double base = 1.5;
double l0 = log (m_arg1) / log (base);
double l1 = log (m_arg2) / log (base);
return pow (base, l0 + controlValue * (l1 - l0));
}

//------------------------------------------------------------------------------

double ParamInfo::Pow2_toControlValue (double nativeValue) const
{
return ((log (nativeValue) / log (2.)) - m_arg1) / (m_arg2 - m_arg1);
}

double ParamInfo::Pow2_toNativeValue (double controlValue) const
{
return pow (2., (controlValue * (m_arg2 - m_arg1)) + m_arg1);
}

//------------------------------------------------------------------------------

std::string ParamInfo::Int_toString (double nativeValue) const
{
std::ostringstream os;
os << int (nativeValue);
return os.str();
}

std::string ParamInfo::Hz_toString (double nativeValue) const
{
std::ostringstream os;
os << int (nativeValue) << " Hz";
return os.str();
}

std::string ParamInfo::Real_toString (double nativeValue) const
{
std::ostringstream os;
os << std::fixed << std::setprecision(3) << nativeValue;
return os.str();
}

std::string ParamInfo::Db_toString (double nativeValue) const
{
const double af = fabs (nativeValue);
int prec;
if (af < 1)
prec = 3;
else if (af < 10)
prec = 2;
else
prec = 1;
std::ostringstream os;
os << std::fixed << std::setprecision (prec) << nativeValue << " dB";
return os.str();
}

//------------------------------------------------------------------------------

ParamInfo ParamInfo::defaultSampleRateParam ()
{
return ParamInfo (idSampleRate, "Fs", "Sample Rate",
11025, 192000, 44100,
&ParamInfo::Real_toControlValue,
&ParamInfo::Real_toNativeValue,
&ParamInfo::Hz_toString);
}

ParamInfo ParamInfo::defaultCutoffFrequencyParam ()
{
return ParamInfo (idFrequency, "Fc", "Cutoff Frequency",
10, 22040, 2000,
&ParamInfo::Log_toControlValue,
&ParamInfo::Log_toNativeValue,
&ParamInfo::Hz_toString);
}

ParamInfo ParamInfo::defaultCenterFrequencyParam ()
{
return ParamInfo (idFrequency, "Fc", "Center Frequency",
10, 22040, 2000,
&ParamInfo::Log_toControlValue,
&ParamInfo::Log_toNativeValue,
&ParamInfo::Hz_toString);
}

ParamInfo ParamInfo::defaultQParam ()
{
return ParamInfo (idQ, "Q", "Resonance",
-4, 4, 1,
&ParamInfo::Pow2_toControlValue,
&ParamInfo::Pow2_toNativeValue,
&ParamInfo::Real_toString);
}

ParamInfo ParamInfo::defaultBandwidthParam ()
{
return ParamInfo (idBandwidth, "BW", "Bandwidth (Octaves)",
-4, 4, 1,
&ParamInfo::Pow2_toControlValue,
&ParamInfo::Pow2_toNativeValue,
&ParamInfo::Real_toString);
}

ParamInfo ParamInfo::defaultBandwidthHzParam ()
{
return ParamInfo (idBandwidthHz, "BW", "Bandwidth (Hz)",
10, 22040, 1720,
&ParamInfo::Log_toControlValue,
&ParamInfo::Log_toNativeValue,
&ParamInfo::Hz_toString);
}

ParamInfo ParamInfo::defaultGainParam ()
{
return ParamInfo (idGain, "Gain", "Gain",
-24, 24, -6,
&ParamInfo::Real_toControlValue,
&ParamInfo::Real_toNativeValue,
&ParamInfo::Db_toString);
}

ParamInfo ParamInfo::defaultSlopeParam ()
{
return ParamInfo (idSlope, "Slope", "Slope",
-2, 2, 1,
&ParamInfo::Pow2_toControlValue,
&ParamInfo::Pow2_toNativeValue,
&ParamInfo::Real_toString);
}

ParamInfo ParamInfo::defaultRippleDbParam ()
{
return ParamInfo (idRippleDb, "Ripple", "Ripple dB",
0.001, 12, 0.01,
&ParamInfo::Real_toControlValue,
&ParamInfo::Real_toNativeValue,
&ParamInfo::Db_toString);
}

ParamInfo ParamInfo::defaultStopDbParam ()
{
return ParamInfo (idStopDb, "Stop", "Stopband dB",
3, 60, 48,
&ParamInfo::Real_toControlValue,
&ParamInfo::Real_toNativeValue,
&ParamInfo::Db_toString);
}

ParamInfo ParamInfo::defaultRolloffParam ()
{
return ParamInfo (idRolloff, "W", "Transition Width",
-16, 4, 0,
&ParamInfo::Real_toControlValue,
&ParamInfo::Real_toNativeValue,
&ParamInfo::Real_toString);
}

ParamInfo ParamInfo::defaultPoleRhoParam ()
{
return ParamInfo (idPoleRho, "Pd", "Pole Distance",
0, 1, 0.5,
&ParamInfo::Real_toControlValue,
&ParamInfo::Real_toNativeValue,
&ParamInfo::Real_toString);
}

ParamInfo ParamInfo::defaultPoleThetaParam ()
{
return ParamInfo (idPoleTheta, "Pa", "Pole Angle",
0, doublePi, doublePi/2,
&ParamInfo::Real_toControlValue,
&ParamInfo::Real_toNativeValue,
&ParamInfo::Real_toString);
}

ParamInfo ParamInfo::defaultZeroRhoParam ()
{
return ParamInfo (idZeroRho, "Pd", "Zero Distance",
0, 1, 0.5,
&ParamInfo::Real_toControlValue,
&ParamInfo::Real_toNativeValue,
&ParamInfo::Real_toString);
}

ParamInfo ParamInfo::defaultZeroThetaParam ()
{
return ParamInfo (idZeroTheta, "Pa", "Zero Angle",
0, doublePi, doublePi/2,
&ParamInfo::Real_toControlValue,
&ParamInfo::Real_toNativeValue,
&ParamInfo::Real_toString);
}

ParamInfo ParamInfo::defaultPoleRealParam ()
{
return ParamInfo (idPoleReal, "A1", "Pole Real",
-1, 1, 0.25,
&ParamInfo::Real_toControlValue,
&ParamInfo::Real_toNativeValue,
&ParamInfo::Real_toString);
}

ParamInfo ParamInfo::defaultZeroRealParam ()
{
return ParamInfo (idZeroReal, "B1", "Zero Real",
-1, 1, -0.25,
&ParamInfo::Real_toControlValue,
&ParamInfo::Real_toNativeValue,
&ParamInfo::Real_toString);
}
}


+ 337
- 0
ports-juce6/roth-air/DspFilters/source/PoleFilter.cpp View File

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

"A Collection of Useful C++ Classes for Digital Signal Processing"
By Vincent Falco

Official project location:
http://code.google.com/p/dspfilterscpp/

See Documentation.cpp for contact information, notes, and bibliography.

--------------------------------------------------------------------------------

License: MIT License (http://www.opensource.org/licenses/mit-license.php)
Copyright (c) 2009 by Vincent Falco

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 "DspFilters/Common.h"
#include "DspFilters/PoleFilter.h"

namespace Dsp {

//------------------------------------------------------------------------------

complex_t LowPassTransform::transform (complex_t c)
{
if (c == infinity())
return complex_t (-1, 0);

// frequency transform
c = f * c;
// bilinear low pass transform
return (1. + c) / (1. - c);
}

LowPassTransform::LowPassTransform (double fc,
LayoutBase& digital,
LayoutBase const& analog)
{
digital.reset ();

// prewarp
f = tan (doublePi * fc);

const int numPoles = analog.getNumPoles ();
const int pairs = numPoles / 2;
for (int i = 0; i < pairs; ++i)
{
const PoleZeroPair& pair = analog[i];
digital.addPoleZeroConjugatePairs (transform (pair.poles.first),
transform (pair.zeros.first));
}

if (numPoles & 1)
{
const PoleZeroPair& pair = analog[pairs];
digital.add (transform (pair.poles.first),
transform (pair.zeros.first));
}

digital.setNormal (analog.getNormalW(),
analog.getNormalGain());
}

//------------------------------------------------------------------------------

complex_t HighPassTransform::transform (complex_t c)
{
if (c == infinity())
return complex_t (1, 0);

// frequency transform
c = f * c;

// bilinear high pass transform
return - (1. + c) / (1. - c);
}

HighPassTransform::HighPassTransform (double fc,
LayoutBase& digital,
LayoutBase const& analog)
{
digital.reset ();

// prewarp
f = 1. / tan (doublePi * fc);

const int numPoles = analog.getNumPoles ();
const int pairs = numPoles / 2;
for (int i = 0; i < pairs; ++i)
{
const PoleZeroPair& pair = analog[i];
digital.addPoleZeroConjugatePairs (transform (pair.poles.first),
transform (pair.zeros.first));
}
if (numPoles & 1)
{
const PoleZeroPair& pair = analog[pairs];
digital.add (transform (pair.poles.first),
transform (pair.zeros.first));
}

digital.setNormal (doublePi - analog.getNormalW(),
analog.getNormalGain());
}

//------------------------------------------------------------------------------

BandPassTransform::BandPassTransform (double fc,
double fw,
LayoutBase& digital,
LayoutBase const& analog)
{
// handle degenerate cases efficiently
// THIS DOESNT WORK because the cascade states won't match
#if 0
const double fw_2 = fw / 2;
if (fc - fw_2 < 0)
{
LowPassTransform::transform (fc + fw_2, digital, analog);
}
else if (fc + fw_2 >= 0.5)
{
HighPassTransform::transform (fc - fw_2, digital, analog);
}
else
#endif

digital.reset ();

const double ww = 2 * doublePi * fw;

// pre-calcs
wc2 = 2 * doublePi * fc - (ww / 2);
wc = wc2 + ww;

// what is this crap?
if (wc2 < 1e-8)
wc2 = 1e-8;
if (wc > doublePi-1e-8)
wc = doublePi-1e-8;

a = cos ((wc + wc2) * 0.5) /
cos ((wc - wc2) * 0.5);
b = 1 / tan ((wc - wc2) * 0.5);
a2 = a * a;
b2 = b * b;
ab = a * b;
ab_2 = 2 * ab;

const int numPoles = analog.getNumPoles ();
const int pairs = numPoles / 2;
for (int i = 0; i < pairs; ++i)
{
const PoleZeroPair& pair = analog[i];
ComplexPair p1 = transform (pair.poles.first);
ComplexPair z1 = transform (pair.zeros.first);

//
// Optimize out the calculations for conjugates for Release builds
//
#ifndef NDEBUG
ComplexPair p2 = transform (pair.poles.second);
ComplexPair z2 = transform (pair.zeros.second);
assert (p2.first == std::conj (p1.first));
assert (p2.second == std::conj (p1.second));
#endif

digital.addPoleZeroConjugatePairs (p1.first, z1.first);
digital.addPoleZeroConjugatePairs (p1.second, z1.second);
}

if (numPoles & 1)
{
ComplexPair poles = transform (analog[pairs].poles.first);
ComplexPair zeros = transform (analog[pairs].zeros.first);

digital.add (poles, zeros);
}

double wn = analog.getNormalW();
digital.setNormal (2 * atan (sqrt (tan ((wc + wn)* 0.5) * tan((wc2 + wn)* 0.5))),
analog.getNormalGain());
}

ComplexPair BandPassTransform::transform (complex_t c)
{
if (c == infinity())
return ComplexPair (-1, 1);

c = (1. + c) / (1. - c); // bilinear

complex_t v = 0;
v = addmul (v, 4 * (b2 * (a2 - 1) + 1), c);
v += 8 * (b2 * (a2 - 1) - 1);
v *= c;
v += 4 * (b2 * (a2 - 1) + 1);
v = std::sqrt (v);

complex_t u = -v;
u = addmul (u, ab_2, c);
u += ab_2;

v = addmul (v, ab_2, c);
v += ab_2;

complex_t d = 0;
d = addmul (d, 2 * (b - 1), c) + 2 * (1 + b);

return ComplexPair (u/d, v/d);
}

//------------------------------------------------------------------------------

BandStopTransform::BandStopTransform (double fc,
double fw,
LayoutBase& digital,
LayoutBase const& analog)
{
digital.reset ();

const double ww = 2 * doublePi * fw;

wc2 = 2 * doublePi * fc - (ww / 2);
wc = wc2 + ww;

// this is crap
if (wc2 < 1e-8)
wc2 = 1e-8;
if (wc > doublePi-1e-8)
wc = doublePi-1e-8;

a = cos ((wc + wc2) * .5) /
cos ((wc - wc2) * .5);
b = tan ((wc - wc2) * .5);
a2 = a * a;
b2 = b * b;

const int numPoles = analog.getNumPoles ();
const int pairs = numPoles / 2;
for (int i = 0; i < pairs; ++i)
{
const PoleZeroPair& pair = analog[i];
ComplexPair p = transform (pair.poles.first);
ComplexPair z = transform (pair.zeros.first);

//
// Optimize out the calculations for conjugates for Release builds
//
#ifdef NDEBUG
// trick to get the conjugate
if (z.second == z.first)
z.second = std::conj (z.first);

#else
// Do the full calculation to verify correctness
ComplexPair pc = transform (analog[i].poles.second);
ComplexPair zc = transform (analog[i].zeros.second);

// get the conjugates into pc and zc
if (zc.first == z.first)
std::swap (zc.first, zc.second);

assert (pc.first == std::conj (p.first));
assert (pc.second == std::conj (p.second));
assert (zc.first == std::conj (z.first));
assert (zc.second == std::conj (z.second));

#endif

digital.addPoleZeroConjugatePairs (p.first, z.first);
digital.addPoleZeroConjugatePairs (p.second, z.second);
}

if (numPoles & 1)
{
ComplexPair poles = transform (analog[pairs].poles.first);
ComplexPair zeros = transform (analog[pairs].zeros.first);

digital.add (poles, zeros);
}

if (fc < 0.25)
digital.setNormal (doublePi, analog.getNormalGain());
else
digital.setNormal (0, analog.getNormalGain());
}

ComplexPair BandStopTransform::transform (complex_t c)
{
if (c == infinity())
c = -1;
else
c = (1. + c) / (1. - c); // bilinear

complex_t u (0);
u = addmul (u, 4 * (b2 + a2 - 1), c);
u += 8 * (b2 - a2 + 1);
u *= c;
u += 4 * (a2 + b2 - 1);
u = std::sqrt (u);

complex_t v = u * -.5;
v += a;
v = addmul (v, -a, c);

u *= .5;
u += a;
u = addmul (u, -a, c);
complex_t d (b + 1);
d = addmul (d, b-1, c);

return ComplexPair (u/d, v/d);
}

}

+ 207
- 0
ports-juce6/roth-air/DspFilters/source/RBJ.cpp View File

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

"A Collection of Useful C++ Classes for Digital Signal Processing"
By Vincent Falco

Official project location:
http://code.google.com/p/dspfilterscpp/

See Documentation.cpp for contact information, notes, and bibliography.

--------------------------------------------------------------------------------

License: MIT License (http://www.opensource.org/licenses/mit-license.php)
Copyright (c) 2009 by Vincent Falco

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 "DspFilters/Common.h"
#include "DspFilters/RBJ.h"

namespace Dsp {

namespace RBJ {

void LowPass::setup (double sampleRate,
double cutoffFrequency,
double q)
{
double w0 = 2 * doublePi * cutoffFrequency / sampleRate;
double cs = cos (w0);
double sn = sin (w0);
double AL = sn / (2 * q);
double b0 = (1 - cs) / 2;
double b1 = 1 - cs;
double b2 = (1 - cs) / 2;
double a0 = 1 + AL;
double a1 = -2 * cs;
double a2 = 1 - AL;
setCoefficients (a0, a1, a2, b0, b1, b2);
}

void HighPass::setup (double sampleRate,
double cutoffFrequency,
double q)
{
double w0 = 2 * doublePi * cutoffFrequency / sampleRate;
double cs = cos (w0);
double sn = sin (w0);
double AL = sn / ( 2 * q );
double b0 = (1 + cs) / 2;
double b1 = -(1 + cs);
double b2 = (1 + cs) / 2;
double a0 = 1 + AL;
double a1 = -2 * cs;
double a2 = 1 - AL;
setCoefficients (a0, a1, a2, b0, b1, b2);
}

void BandPass1::setup (double sampleRate,
double centerFrequency,
double bandWidth)
{
double w0 = 2 * doublePi * centerFrequency / sampleRate;
double cs = cos (w0);
double sn = sin (w0);
double AL = sn / ( 2 * bandWidth );
double b0 = bandWidth * AL;// sn / 2;
double b1 = 0;
double b2 = -bandWidth * AL;//-sn / 2;
double a0 = 1 + AL;
double a1 = -2 * cs;
double a2 = 1 - AL;
setCoefficients (a0, a1, a2, b0, b1, b2);
}

void BandPass2::setup (double sampleRate,
double centerFrequency,
double bandWidth)
{
double w0 = 2 * doublePi * centerFrequency / sampleRate;
double cs = cos (w0);
double sn = sin (w0);
double AL = sn / ( 2 * bandWidth );
double b0 = AL;
double b1 = 0;
double b2 = -AL;
double a0 = 1 + AL;
double a1 = -2 * cs;
double a2 = 1 - AL;
setCoefficients (a0, a1, a2, b0, b1, b2);
}

void BandStop::setup (double sampleRate,
double centerFrequency,
double bandWidth)
{
double w0 = 2 * doublePi * centerFrequency / sampleRate;
double cs = cos (w0);
double sn = sin (w0);
double AL = sn / ( 2 * bandWidth );
double b0 = 1;
double b1 = -2 * cs;
double b2 = 1;
double a0 = 1 + AL;
double a1 = -2 * cs;
double a2 = 1 - AL;
setCoefficients (a0, a1, a2, b0, b1, b2);
}

void LowShelf::setup (double sampleRate,
double cutoffFrequency,
double gainDb,
double shelfSlope)
{
double A = pow (10, gainDb/40);
double w0 = 2 * doublePi * cutoffFrequency / sampleRate;
double cs = cos (w0);
double sn = sin (w0);
double AL = sn / 2 * ::std::sqrt ((A + 1/A) * (1/shelfSlope - 1) + 2);
double sq = 2 * sqrt(A) * AL;
double b0 = A*( (A+1) - (A-1)*cs + sq );
double b1 = 2*A*( (A-1) - (A+1)*cs );
double b2 = A*( (A+1) - (A-1)*cs - sq );
double a0 = (A+1) + (A-1)*cs + sq;
double a1 = -2*( (A-1) + (A+1)*cs );
double a2 = (A+1) + (A-1)*cs - sq;
setCoefficients (a0, a1, a2, b0, b1, b2);
}

void HighShelf::setup (double sampleRate,
double cutoffFrequency,
double gainDb,
double shelfSlope)
{
double A = pow (10, gainDb/40);
double w0 = 2 * doublePi * cutoffFrequency / sampleRate;
double cs = cos (w0);
double sn = sin (w0);
double AL = sn / 2 * ::std::sqrt ((A + 1/A) * (1/shelfSlope - 1) + 2);
double sq = 2 * sqrt(A) * AL;
double b0 = A*( (A+1) - (A-1)*cs + sq );
double b1 = -2*A*( (A-1) - (A+1)*cs );
double b2 = A*( (A+1) - (A-1)*cs - sq );
double a0 = (A+1) + (A-1)*cs + sq;
double a1 = 2*( (A-1) + (A+1)*cs );
double a2 = (A+1) + (A-1)*cs - sq;
setCoefficients (a0, a1, a2, b0, b1, b2);
}

void BandShelf::setup (double sampleRate,
double centerFrequency,
double gainDb,
double bandWidth)
{
double A = pow (10, gainDb/40);
double w0 = 2 * doublePi * centerFrequency / sampleRate;
double cs = cos(w0);
double sn = sin(w0);
double AL = sn * sinh( doubleLn2/2 * bandWidth * w0/sn );
assert (!Dsp::is_nan (AL));
double b0 = 1 + AL * A;
double b1 = -2 * cs;
double b2 = 1 - AL * A;
double a0 = 1 + AL / A;
double a1 = -2 * cs;
double a2 = 1 - AL / A;
setCoefficients (a0, a1, a2, b0, b1, b2);
}

void AllPass::setup (double sampleRate,
double phaseFrequency,
double q)
{
double w0 = 2 * doublePi * phaseFrequency / sampleRate;
double cs = cos (w0);
double sn = sin (w0);
double AL = sn / ( 2 * q );
double b0 = 1 - AL;
double b1 = -2 * cs;
double b2 = 1 + AL;
double a0 = 1 + AL;
double a1 = -2 * cs;
double a2 = 1 - AL;
setCoefficients (a0, a1, a2, b0, b1, b2);
}

}

}

+ 188
- 0
ports-juce6/roth-air/DspFilters/source/RootFinder.cpp View File

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

"A Collection of Useful C++ Classes for Digital Signal Processing"
By Vincent Falco

Official project location:
http://code.google.com/p/dspfilterscpp/

See Documentation.cpp for contact information, notes, and bibliography.

--------------------------------------------------------------------------------

License: MIT License (http://www.opensource.org/licenses/mit-license.php)
Copyright (c) 2009 by Vincent Falco

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 "DspFilters/Common.h"
#include "DspFilters/RootFinder.h"
#include <stdexcept>
#include <algorithm>

namespace Dsp {

void RootFinderBase::solve (int degree,
bool polish,
bool doSort)
{
assert (degree <= m_maxdegree);

const double EPS = 1.0e-30;

int its;
complex_t x, b, c;

int m = degree;

// copy coefficients
for (int j = 0; j <= m; ++j)
m_ad[j] = m_a[j];

// for each root
for (int j = m - 1; j >= 0; --j)
{
// initial guess at 0
x = 0.0;
laguerre (j + 1, m_ad, x, its);
if (fabs (std::imag(x)) <= 2.0 * EPS * fabs (std::real(x)))
x = complex_t (std::real(x), 0.0);

m_root[j] = x;

// deflate
b = m_ad[j+1];
for (int jj = j; jj >= 0; --jj)
{
c = m_ad[jj];
m_ad[jj] = b;
b = x * b + c;
}
}

if (polish)
for (int j = 0; j < m; ++j)
laguerre (degree, m_a, m_root[j], its);

if (doSort)
sort (degree);
}

void RootFinderBase::sort (int degree)
{
for (int j = 1; j < degree; ++j)
{
complex_t x = m_root[j];

int i;
for (i = j - 1; i >= 0; --i )
{
if (m_root[i].imag() >= x.imag())
break;

m_root[i+1] = m_root[i];
}

m_root[i+1] = x;
}
}

//------------------------------------------------------------------------------

void RootFinderBase::laguerre (int degree,
complex_t a[],
complex_t& x,
int& its)
{
const int MR = 8, MT = 10, MAXIT = MT * MR;
const double EPS = std::numeric_limits<double>::epsilon();

static const double frac[MR + 1] =
{0.0, 0.5, 0.25, 0.75, 0.13, 0.38, 0.62, 0.88, 1.0};

complex_t dx, x1, b, d, f, g, h, sq, gp, gm, g2;

int m = degree;
for (int iter = 1; iter <= MAXIT; ++iter)
{
its = iter;
b = a[m];
double err = std::abs(b);
d = f = 0.0;
double abx = std::abs(x);
for (int j = m - 1; j >= 0; --j)
{
f = x * f + d;
d = x * d + b;
b = x * b + a[j];
err = std::abs(b) + abx * err;
}
err *= EPS;
if (std::abs(b) <= err)
return;
g = d / b;
g2 = g * g;
h = g2 - 2.0 * f / b;
sq = sqrt (double(m - 1) * (double(m) * h - g2));
gp = g + sq;
gm = g - sq;
double abp = std::abs (gp);
double abm = std::abs (gm);
if (abp < abm)
gp = gm;
dx = std::max(abp, abm) > 0.0 ? double(m) / gp : std::polar (1 + abx, double(iter));
x1 = x - dx;
if (x == x1)
return;
if (iter % MT != 0)
x = x1;
else
x -= frac[iter / MT] * dx;
}

throw std::logic_error ("laguerre failed");
}

//------------------------------------------------------------------------------

complex_t RootFinderBase::eval (int degree,
const complex_t& x )
{
complex_t y;

if (x != 0.)
{
for (int i = 0; i <= degree; ++i)
y += m_a[i] * pow (x, double(i));
}
else
{
y = m_a[0];
}

return y;
}


}

+ 43
- 0
ports-juce6/roth-air/DspFilters/source/State.cpp View File

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

"A Collection of Useful C++ Classes for Digital Signal Processing"
By Vincent Falco

Official project location:
http://code.google.com/p/dspfilterscpp/

See Documentation.cpp for contact information, notes, and bibliography.

--------------------------------------------------------------------------------

License: MIT License (http://www.opensource.org/licenses/mit-license.php)
Copyright (c) 2009 by Vincent Falco

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 "DspFilters/Common.h"
#include "DspFilters/State.h"

namespace Dsp {

//------------------------------------------------------------------------------

}

BIN
ports-juce6/roth-air/Graphics/airText.png View File

Before After
Width: 120  |  Height: 72  |  Size: 22KB

BIN
ports-juce6/roth-air/Graphics/bigKnob.png View File

Before After
Width: 290  |  Height: 290  |  Size: 46KB

BIN
ports-juce6/roth-air/Graphics/bigKnob_light.png View File

Before After
Width: 290  |  Height: 290  |  Size: 59KB

BIN
ports-juce6/roth-air/Graphics/bigKnob_red.png View File

Before After
Width: 290  |  Height: 290  |  Size: 38KB

BIN
ports-juce6/roth-air/Graphics/label_freq.png View File

Before After
Width: 130  |  Height: 130  |  Size: 21KB

BIN
ports-juce6/roth-air/Graphics/label_gain.png View File

Before After
Width: 130  |  Height: 130  |  Size: 21KB

BIN
ports-juce6/roth-air/Graphics/label_mix.png View File

Before After
Width: 130  |  Height: 130  |  Size: 21KB

BIN
ports-juce6/roth-air/Graphics/label_thresh.png View File

Before After
Width: 130  |  Height: 130  |  Size: 21KB

BIN
ports-juce6/roth-air/Graphics/smallKnob.png View File

Before After
Width: 130  |  Height: 130  |  Size: 31KB

BIN
ports-juce6/roth-air/Graphics/smallKnob_light.png View File

Before After
Width: 130  |  Height: 130  |  Size: 30KB

BIN
ports-juce6/roth-air/Graphics/title.png View File

Before After
Width: 252  |  Height: 62  |  Size: 24KB

BIN
ports-juce6/roth-air/Graphics/website.png View File

Before After
Width: 215  |  Height: 25  |  Size: 23KB

+ 33
- 0
ports-juce6/roth-air/JuceHeader.h View File

@@ -0,0 +1,33 @@
/*
IMPORTANT! This file is auto-generated each time you save your
project - if you alter its contents, your changes may be overwritten!
This is the header file that your files should include in order to get all the
JUCE library headers. You should avoid including the JUCE headers directly in
your own source files, because that wouldn't pick up the correct configuration
options for your app.
*/
#pragma once
#include "JucePluginMain.h"
#include "BinaryData.h"
#if ! DONT_SET_USING_JUCE_NAMESPACE
// If your code uses a lot of JUCE classes, then this will obviously save you
// a lot of typing, but can be disabled by setting DONT_SET_USING_JUCE_NAMESPACE.
using namespace juce;
#endif
#if ! JUCE_DONT_DECLARE_PROJECTINFO
namespace ProjectInfo
{
const char* const projectName = "Roth-AIR";
const char* const companyName = "Rothmann";
const char* const versionString = "1.1.1";
const int versionNumber = 0x10101;
}
#endif

+ 151
- 0
ports-juce6/roth-air/JucePluginCharacteristics.h View File

@@ -0,0 +1,151 @@
/*
IMPORTANT! This file is auto-generated each time you save your
project - if you alter its contents, your changes may be overwritten!
*/
#pragma once
//==============================================================================
// Audio plugin settings..
#ifndef JucePlugin_Enable_IAA
#define JucePlugin_Enable_IAA 0
#endif
#ifndef JucePlugin_Name
#define JucePlugin_Name "Roth-AIR"
#endif
#ifndef JucePlugin_Desc
#define JucePlugin_Desc "A mixing tool for adding airy, crispy presence"
#endif
#ifndef JucePlugin_Manufacturer
#define JucePlugin_Manufacturer "Rothmann"
#endif
#ifndef JucePlugin_ManufacturerWebsite
#define JucePlugin_ManufacturerWebsite "www.danielrothmann.com"
#endif
#ifndef JucePlugin_ManufacturerEmail
#define JucePlugin_ManufacturerEmail "daniel@danielrothmann.com"
#endif
#ifndef JucePlugin_ManufacturerCode
#define JucePlugin_ManufacturerCode 0x526f7468
#endif
#ifndef JucePlugin_PluginCode
#define JucePlugin_PluginCode 0x4a367663
#endif
#ifndef JucePlugin_IsSynth
#define JucePlugin_IsSynth 0
#endif
#ifndef JucePlugin_WantsMidiInput
#define JucePlugin_WantsMidiInput 0
#endif
#ifndef JucePlugin_ProducesMidiOutput
#define JucePlugin_ProducesMidiOutput 0
#endif
#ifndef JucePlugin_IsMidiEffect
#define JucePlugin_IsMidiEffect 0
#endif
#ifndef JucePlugin_EditorRequiresKeyboardFocus
#define JucePlugin_EditorRequiresKeyboardFocus 0
#endif
#ifndef JucePlugin_Version
#define JucePlugin_Version 1.1.1
#endif
#ifndef JucePlugin_VersionCode
#define JucePlugin_VersionCode 0x10101
#endif
#ifndef JucePlugin_VersionString
#define JucePlugin_VersionString "1.1.1"
#endif
#ifndef JucePlugin_VSTUniqueID
#define JucePlugin_VSTUniqueID JucePlugin_PluginCode
#endif
#ifndef JucePlugin_VSTCategory
#define JucePlugin_VSTCategory kPlugCategEffect
#endif
#ifndef JucePlugin_Vst3Category
#define JucePlugin_Vst3Category "Fx|Dynamics"
#endif
#ifndef JucePlugin_AUMainType
#define JucePlugin_AUMainType 'aufx'
#endif
#ifndef JucePlugin_AUSubType
#define JucePlugin_AUSubType JucePlugin_PluginCode
#endif
#ifndef JucePlugin_AUExportPrefix
#define JucePlugin_AUExportPrefix AIRAU
#endif
#ifndef JucePlugin_AUExportPrefixQuoted
#define JucePlugin_AUExportPrefixQuoted "AIRAU"
#endif
#ifndef JucePlugin_AUManufacturerCode
#define JucePlugin_AUManufacturerCode JucePlugin_ManufacturerCode
#endif
#ifndef JucePlugin_CFBundleIdentifier
#define JucePlugin_CFBundleIdentifier com.Rothmann.Roth-AIR
#endif
#ifndef JucePlugin_RTASCategory
#define JucePlugin_RTASCategory 0
#endif
#ifndef JucePlugin_RTASManufacturerCode
#define JucePlugin_RTASManufacturerCode JucePlugin_ManufacturerCode
#endif
#ifndef JucePlugin_RTASProductId
#define JucePlugin_RTASProductId JucePlugin_PluginCode
#endif
#ifndef JucePlugin_RTASDisableBypass
#define JucePlugin_RTASDisableBypass 0
#endif
#ifndef JucePlugin_RTASDisableMultiMono
#define JucePlugin_RTASDisableMultiMono 0
#endif
#ifndef JucePlugin_AAXIdentifier
#define JucePlugin_AAXIdentifier com.Rothmann.Roth-AIR
#endif
#ifndef JucePlugin_AAXManufacturerCode
#define JucePlugin_AAXManufacturerCode JucePlugin_ManufacturerCode
#endif
#ifndef JucePlugin_AAXProductId
#define JucePlugin_AAXProductId JucePlugin_PluginCode
#endif
#ifndef JucePlugin_AAXCategory
#define JucePlugin_AAXCategory 2
#endif
#ifndef JucePlugin_AAXDisableBypass
#define JucePlugin_AAXDisableBypass 0
#endif
#ifndef JucePlugin_AAXDisableMultiMono
#define JucePlugin_AAXDisableMultiMono 0
#endif
#ifndef JucePlugin_IAAType
#define JucePlugin_IAAType 0x61757278
#endif
#ifndef JucePlugin_IAASubType
#define JucePlugin_IAASubType JucePlugin_PluginCode
#endif
#ifndef JucePlugin_IAAName
#define JucePlugin_IAAName "Rothmann: Roth-AIR"
#endif
#ifndef JucePlugin_VSTNumMidiInputs
#define JucePlugin_VSTNumMidiInputs 16
#endif
#ifndef JucePlugin_VSTNumMidiOutputs
#define JucePlugin_VSTNumMidiOutputs 16
#endif
#ifndef JucePlugin_MaxNumInputChannels
#define JucePlugin_MaxNumInputChannels 2
#endif
#ifndef JucePlugin_MaxNumOutputChannels
#define JucePlugin_MaxNumOutputChannels 2
#endif
#ifndef JucePlugin_PreferredChannelConfigurations
#define JucePlugin_PreferredChannelConfigurations {1, 1},{2, 2}
#endif
#define JucePlugin_LV2URI "http://danielrothmann.com/Roth-AIR"
#define JucePlugin_LV2Category "DynamicsPlugin"
#define JucePlugin_WantsLV2Latency 0
#define JucePlugin_WantsLV2State 0
#define JucePlugin_WantsLV2TimePos 0
#define JucePlugin_WantsLV2Presets 0

+ 621
- 0
ports-juce6/roth-air/LICENSE View File

@@ -0,0 +1,621 @@
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007

Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.

Preamble

The GNU General Public License is a free, copyleft license for
software and other kinds of works.

The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.

When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.

To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.

For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.

Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.

For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.

Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.

Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.

The precise terms and conditions for copying, distribution and
modification follow.

TERMS AND CONDITIONS

0. Definitions.

"This License" refers to version 3 of the GNU General Public License.

"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.

"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.

To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.

A "covered work" means either the unmodified Program or a work based
on the Program.

To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.

To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.

An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.

1. Source Code.

The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.

A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.

The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.

The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.

The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.

The Corresponding Source for a work in source code form is that
same work.

2. Basic Permissions.

All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.

You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.

Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.

3. Protecting Users' Legal Rights From Anti-Circumvention Law.

No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.

When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.

4. Conveying Verbatim Copies.

You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.

You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.

5. Conveying Modified Source Versions.

You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:

a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.

b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".

c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.

d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.

A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.

6. Conveying Non-Source Forms.

You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:

a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.

b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.

c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.

d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.

e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.

A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.

A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.

"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.

If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).

The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.

Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.

7. Additional Terms.

"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.

When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.

Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:

a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or

b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or

c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or

d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or

e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or

f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.

All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.

If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.

Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.

8. Termination.

You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).

However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.

Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.

Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.

9. Acceptance Not Required for Having Copies.

You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.

10. Automatic Licensing of Downstream Recipients.

Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.

An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.

You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.

11. Patents.

A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".

A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.

Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.

In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.

If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.

If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.

A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.

Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.

12. No Surrender of Others' Freedom.

If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.

13. Use with the GNU Affero General Public License.

Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.

14. Revised Versions of this License.

The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.

Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.

If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.

Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.

15. Disclaimer of Warranty.

THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.

16. Limitation of Liability.

IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.

17. Interpretation of Sections 15 and 16.

If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.

END OF TERMS AND CONDITIONS

+ 289
- 0
ports-juce6/roth-air/PluginEditor.cpp View File

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

Plugin editor
================
A Juce class containing the Roth-AIR GUI elements
By Daniel Rothmann

Provided under GNU General Public license:
http://www.gnu.org/licenses/

------------------------------------------------------------------------------
*/

#include "PluginProcessor.h"
#include "PluginEditor.h"

//==============================================================================
AirAudioProcessorEditor::AirAudioProcessorEditor (AirAudioProcessor& p)
: AudioProcessorEditor (&p), processor (p)
{
// Make sure that before the constructor has finished, you've set the
// editor's size to whatever you need it to be.
setSize (581, 345);
setResizable(false, false);

// Set Threshold slider params
threshSlider.setSliderStyle(Slider::RotaryHorizontalVerticalDrag);
threshSlider.setRange(processor.cThreshold->range.start, processor.cThreshold->range.end);
threshSlider.setTextBoxStyle(Slider::NoTextBox, true, 50, 15);
threshSlider.setPopupDisplayEnabled(false, false, this);
threshSlider.setTextValueSuffix(" dB");
threshSlider.setValue(*processor.cThreshold);
threshSlider.setLookAndFeel(&rothLookAndFeel);

// Set crossover freq slider params
crossSlider.setSliderStyle(Slider::RotaryHorizontalVerticalDrag);
crossSlider.setRange(processor.crossFreq->range.start, processor.crossFreq->range.end);
crossSlider.setTextBoxStyle(Slider::NoTextBox, true, 50, 15);
crossSlider.setPopupDisplayEnabled(false, false, this);
crossSlider.setTextValueSuffix(" Hz");
crossSlider.setValue(*processor.crossFreq);
crossSlider.setLookAndFeel(&rothLookAndFeel);

// Set Gain slider params
gainSlider.setSliderStyle(Slider::RotaryHorizontalVerticalDrag);
gainSlider.setRange(processor.hpGain->range.start, processor.hpGain->range.end);
gainSlider.setTextBoxStyle(Slider::NoTextBox, true, 50, 15);
gainSlider.setPopupDisplayEnabled(false, false, this);
gainSlider.setTextValueSuffix(" Rms");
gainSlider.setValue(*processor.hpGain);
gainSlider.setLookAndFeel(&rothLookAndFeel);

// Set Dry/Wet slider params
dryWetSlider.setSliderStyle(Slider::RotaryHorizontalVerticalDrag);
dryWetSlider.setRange(processor.dryWet->range.start, processor.dryWet->range.end);
dryWetSlider.setTextBoxStyle(Slider::NoTextBox, true, 50, 15);
dryWetSlider.setPopupDisplayEnabled(false, false, this);
dryWetSlider.setTextValueSuffix(" %");
dryWetSlider.setValue(*processor.dryWet);
dryWetSlider.setLookAndFeel(&rothLookAndFeel);

// Set AIR slider params
airSlider.setSliderStyle(Slider::RotaryHorizontalVerticalDrag);
airSlider.setRange(processor.airAmt->range.start, processor.airAmt->range.end);
airSlider.setTextBoxStyle(Slider::NoTextBox, true, 50, 15);
airSlider.setPopupDisplayEnabled(false, false, this);
airSlider.setTextValueSuffix(" %");
airSlider.setValue(*processor.airAmt);
airSlider.setLookAndFeel(&rothLookAndFeel);

// Add and make sliders visible
addAndMakeVisible(&threshSlider);
addAndMakeVisible(&crossSlider);
addAndMakeVisible(&gainSlider);
addAndMakeVisible(&dryWetSlider);
addAndMakeVisible(&airSlider);
// Add listeners for sliders
threshSlider.addListener(this);
crossSlider.addListener(this);
gainSlider.addListener(this);
dryWetSlider.addListener(this);
airSlider.addListener(this);

for (int i = 0; i < meterBufferSize; i++)
{
arrGainReduction.add(0.);
}

// Start a timer - this is how often the GUI will be updated when params are automated from host (60"fps")
startTimerHz(60);
}

AirAudioProcessorEditor::~AirAudioProcessorEditor()
{
}

//==============================================================================
void AirAudioProcessorEditor::paint (Graphics& g)
{
// g.fillAll (Colours::white);
g.fillAll(Colour::fromRGB(62, 75, 89));

g.setColour (Colour::fromRGB(152, 193, 217));
g.setFont (17.0f);

// Draw GUI images
g.drawImage(title, 0, 5, 252, 62, 0, 0, 252, 62);
g.drawImage(website, 354, 34, 215, 25, 0, 0, 215, 25);

// draws labels if the "show-x-" is false - if its true it draws param value as text (truncated string)
if (!showThresh)
g.drawImage(threshLabel, 10, 64, 130, 130, 0, 0, 130, 130);
else
g.drawText(std::to_string(processor.getThreshold()).substr(0,5) + " dB", 10, 64, 130, 130, juce::Justification::centred);

if (!showCross)
g.drawImage(freqLabel, 10, 204, 130, 130, 0, 0, 130, 130);
else
g.drawText(std::to_string(processor.getCrossFreq()).substr(0, 4) + " Hz", 10, 204, 130, 130, juce::Justification::centred);

if (!showGain)
g.drawImage(gainLabel, 440, 64, 130, 130, 0, 0, 130, 130);
else
g.drawText(std::to_string(processor.getHpGain()).substr(0, 4), 440, 64, 130, 130, juce::Justification::centred);

if(!showMix)
g.drawImage(mixLabel, 440, 204, 130, 130, 0, 0, 130, 130);
else
g.drawText(std::to_string(processor.getDryWet() * 100).substr(0, 4) + "%", 440, 204, 130, 130, juce::Justification::centred);

// Image redLightCopy = redLight.createCopy();
// redLightCopy.multiplyAllAlphas(gainReduction);
g.beginTransparencyLayer(gainReduction);
g.drawImage(redLight, 145, 54, 290, 290, 0, 0, 290, 290);
g.endTransparencyLayer();

g.drawImage(airText, 230, 164, 120, 72, 0, 0, 120, 72);
}

void AirAudioProcessorEditor::resized()
{
// This is generally where you'll want to lay out the positions of any
// subcomponents in your editor..

// Place the knobs (sliders) and set size
threshSlider.setBounds(10, 64, 130, 130);
crossSlider.setBounds(10, 204, 130, 130);
gainSlider.setBounds(440, 64, 130, 130);
dryWetSlider.setBounds(440, 204, 130, 130);
airSlider.setBounds(145, 54, 290, 290);
}

// When a slider is changed, set according parameter to new slider value
void AirAudioProcessorEditor::sliderValueChanged(Slider* slider)
{
if (slider == &crossSlider)
{
*processor.crossFreq = crossSlider.getValue();
}
else if (slider == &dryWetSlider)
{
*processor.dryWet = dryWetSlider.getValue();
}
else if (slider == &threshSlider)
{
*processor.cThreshold = threshSlider.getValue();
}
else if (slider == &gainSlider)
{
*processor.hpGain = gainSlider.getValue();
}
else if (slider == &airSlider)
{
*processor.airAmt = airSlider.getValue();
}
}

// Tell the parameter that user has started dragging slider
void AirAudioProcessorEditor::sliderDragStarted(Slider* slider)
{
if (slider == &crossSlider)
{
processor.crossFreq->beginChangeGesture();
showCross = true;
}
else if (slider == &dryWetSlider)
{
processor.dryWet->beginChangeGesture();
showMix = true;
}
else if (slider == &threshSlider)
{
processor.cThreshold->beginChangeGesture();
showThresh = true;
}
else if (slider == &gainSlider)
{
processor.hpGain->beginChangeGesture();
showGain = true;
}
else if (slider == &airSlider)
{
processor.airAmt->beginChangeGesture();
showAir = true;
}
}

// Tell the parameter that user has stopped dragging slider
void AirAudioProcessorEditor::sliderDragEnded(Slider* slider)
{
if (slider == &crossSlider)
{
processor.crossFreq->endChangeGesture();
showCross = false;
}
else if (slider == &dryWetSlider)
{
processor.dryWet->endChangeGesture();
showMix = false;
}
else if (slider == &threshSlider)
{
processor.cThreshold->endChangeGesture();
showThresh = false;
}
else if (slider == &gainSlider)
{
processor.hpGain->endChangeGesture();
showGain = false;
}
else if (slider == &airSlider)
{
processor.airAmt->endChangeGesture();
showAir = false;
}
}

// Update sliders with parameter values with frequency from timer
void AirAudioProcessorEditor::timerCallback()
{
// get parameter values from the processor each timerCallback - to check for automation changes
crossSlider.setValue(processor.getCrossFreq(), dontSendNotification);
dryWetSlider.setValue(processor.getDryWet(), dontSendNotification);
threshSlider.setValue(processor.getThreshold(), dontSendNotification);
gainSlider.setValue(processor.getHpGain(), dontSendNotification);
airSlider.setValue(processor.getAirAmt(), dontSendNotification);

// get current amount of gain reduction from compressor, divide it by 20(dB) and waveshape it for low values to be pushed up
double tempGainReduction = processor.getTempGainReduction() / 15;
tempGainReduction = (1.0 + 4) * tempGainReduction / (1.0 + 4 * abs(tempGainReduction));

// if the gain reduction has changed, do the calculation and order a repaint
if (tempGainReduction != gainReduction)
{
// iterate index (for averaging meter values)
gainIterator++;

if (gainIterator >= arrGainReduction.size())
gainIterator = 0;

// store temporary gain reduction in array at index
// arrGainReduction.getReference(gainIterator) = tempGainReduction;
arrGainReduction.setUnchecked(gainIterator, tempGainReduction);

// init gainReduction value
gainReduction = 0;

// loop through all values in array and add them to gainreduction
for (int i = 0; i < arrGainReduction.size(); i++)
{
// gainReduction += arrGainReduction.getReference(gainIterator);
gainReduction += arrGainReduction.getUnchecked(i);
}

// divide by the size of the array (get the mean of the array)
gainReduction /= arrGainReduction.size();

// make sure it will stay within alpha boundaries
if (gainReduction > 1)
gainReduction = 1;
else if (gainReduction < 0)
gainReduction = 0;

// order repaint of the button area
repaint(145, 54, 290, 290);
}
}

+ 171
- 0
ports-juce6/roth-air/PluginEditor.h View File

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

Plugin editor
================
A Juce class containing the Roth-AIR GUI elements
By Daniel Rothmann

Provided under GNU General Public license:
http://www.gnu.org/licenses/

------------------------------------------------------------------------------
*/

#ifndef PLUGINEDITOR_H_INCLUDED
#define PLUGINEDITOR_H_INCLUDED

#include "JuceHeader.h"
#include "PluginProcessor.h"

//==============================================================================
// Custom look and feel class for bitmap sliders
class RothLookAndFeel : public LookAndFeel_V3
{
public:
RothLookAndFeel()
{
}

void drawRotarySlider(Graphics& g, int x, int y, int width, int height, float sliderPos,
const float rotaryStartAngle, const float rotaryEndAngle, Slider& slider) override
{
// Declare big knob images from Binary Data
Image bigKnob = ImageCache::getFromMemory(BinaryData::bigKnob_png, BinaryData::bigKnob_pngSize);
Image bigLight = ImageCache::getFromMemory(BinaryData::bigKnob_light_png, BinaryData::bigKnob_light_pngSize);

// Declare small knob images from Binary Data
Image smallKnob = ImageCache::getFromMemory(BinaryData::smallKnob_png, BinaryData::smallKnob_pngSize);
Image smallLight = ImageCache::getFromMemory(BinaryData::smallKnob_light_png, BinaryData::smallKnob_light_pngSize);

//value between 0 and 1 for current amount of rotation
const double fractRotation = (slider.getValue() - slider.getMinimum()) / (slider.getMaximum() - slider.getMinimum());

// Apply rotation transform to knob graphic context
AffineTransform rotation = AffineTransform::rotation(fractRotation * 5 - 45, width / 2, height / 2);
g.addTransform(rotation);

// If it's a big knob
if (width >= 200)
{
// Multiply light alphas by fractRotation (0-1)
Image bigLightCopy = bigLight.createCopy();
bigLightCopy.multiplyAllAlphas(fractRotation);

// Draw big light
g.drawImage(bigLightCopy,
x,
y,
width,
height,
0,
0,
bigLight.getWidth(),
bigLight.getHeight());

// Draw big knob
g.drawImage(bigKnob,
x,
y,
width,
height,
0,
0,
bigKnob.getWidth(),
bigKnob.getHeight());
}
else
{
// Multiply light alphas by fractRotation (0-1)
Image smallLightCopy = smallLight.createCopy();
smallLightCopy.multiplyAllAlphas(fractRotation);

// Draw small light
g.drawImage(smallLightCopy,
x,
y,
width,
height,
0,
0,
smallLight.getWidth(),
smallLight.getHeight());

// Draw small knob
g.drawImage(smallKnob,
x,
y,
width,
height,
0,
0,
smallKnob.getWidth(),
smallKnob.getHeight());
}
}
};

//==============================================================================
/**
*/
class AirAudioProcessorEditor : public AudioProcessorEditor,
public Slider::Listener,
public Timer
{
public:
AirAudioProcessorEditor (AirAudioProcessor&);
~AirAudioProcessorEditor();

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

//============================================================================
void sliderValueChanged(Slider* slider) override;
void sliderDragStarted(Slider* slider) override;
void sliderDragEnded(Slider* slider) override;
void timerCallback() override;

private:
// This reference is provided as a quick way for your editor to
// access the processor object that created it.
AirAudioProcessor& processor;
// Slider crossSlider;
Slider dryWetSlider;
Slider crossSlider;
Slider threshSlider;
Slider gainSlider;
Slider airSlider;

// Custom look and feel for gui stuff (subclass in PluginEditor)
RothLookAndFeel rothLookAndFeel;

// GUI image references
Image title = ImageCache::getFromMemory(BinaryData::title_png, BinaryData::title_pngSize);
Image airText = ImageCache::getFromMemory(BinaryData::airText_png, BinaryData::airText_pngSize);
Image website = ImageCache::getFromMemory(BinaryData::website_png, BinaryData::website_pngSize);

Image threshLabel = ImageCache::getFromMemory(BinaryData::label_thresh_png, BinaryData::label_thresh_pngSize);
Image freqLabel = ImageCache::getFromMemory(BinaryData::label_freq_png, BinaryData::label_freq_pngSize);
Image gainLabel = ImageCache::getFromMemory(BinaryData::label_gain_png, BinaryData::label_freq_pngSize);
Image mixLabel = ImageCache::getFromMemory(BinaryData::label_mix_png, BinaryData::label_mix_pngSize);

Image redLight = ImageCache::getFromMemory(BinaryData::bigKnob_red_png, BinaryData::bigKnob_red_pngSize);

bool showCross = false;
bool showMix = false;
bool showThresh = false;
bool showGain = false;
bool showAir = false;

double gainReduction;
int gainIterator = 0;
Array<double> arrGainReduction;
int meterBufferSize = 8;

JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AirAudioProcessorEditor)
};


#endif // PLUGINEDITOR_H_INCLUDED

+ 439
- 0
ports-juce6/roth-air/PluginProcessor.cpp View File

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

Plugin processor
================
A Juce class containing the Roth-AIR plugin parameters and audio processing instructions
By Daniel Rothmann

Provided under GNU General Public license:
http://www.gnu.org/licenses/

------------------------------------------------------------------------------
*/

#include "PluginProcessor.h"
#include "PluginEditor.h"


//==============================================================================
AirAudioProcessor::AirAudioProcessor()
{
// Instanciate plugin parameters
addParameter(crossFreq = new AudioParameterFloat("crossFreq", // param ID
"Crossover Freq", // param name
NormalisableRange<float> (1000.0f, 8000.0f), // param range
4000.0f)); // default value
addParameter(dryWet = new AudioParameterFloat("dryWet",
"Dry / Wet",
NormalisableRange<float>(0.0f, 1.0f),
0.6f));
addParameter(cThreshold = new AudioParameterFloat("threshold",
"Threshold",
NormalisableRange<float>(-40.0f, 0.0f),
-18.0f));
addParameter(hpGain = new AudioParameterFloat("gain",
"Gain",
NormalisableRange<float>(0.25f, 2.0f),
1.0f));
addParameter(airAmt = new AudioParameterFloat("air",
"Air Amt",
NormalisableRange<float>(0.0f, 1.0f),
0.0f));

// Initialize non-parameter variables
hpPreGain = 0.0;
cRatio = 1.0;
airRatioAmt = 3.0;
airGainAmt = 0.0;
airSatAmt = 0.5;
// Instanciate filters
hp = std::make_unique<Dsp::SmoothedFilterDesign <Dsp::Bessel::Design::HighPass<4>, 2, Dsp::DirectFormII>>(1024);
lp = std::make_unique<Dsp::SmoothedFilterDesign <Dsp::Bessel::Design::LowPass<4>, 2, Dsp::DirectFormII>>(1024);

// Instanciate waveshaper
waveShaper = std::make_unique<WaveShaper>(2);
waveShaper->setAmount(0.0);

// Instanciate compressor
pCompressor = std::make_unique<Compressor>(2, 44100);
}

AirAudioProcessor::~AirAudioProcessor()
{
}

//==============================================================================
const String AirAudioProcessor::getName() const
{
return JucePlugin_Name;
}

bool AirAudioProcessor::acceptsMidi() const
{
#if JucePlugin_WantsMidiInput
return true;
#else
return false;
#endif
}

bool AirAudioProcessor::producesMidi() const
{
#if JucePlugin_ProducesMidiOutput
return true;
#else
return false;
#endif
}

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

int AirAudioProcessor::getNumPrograms()
{
return 1; // NB: some hosts don't cope very well if you tell them there are 0 programs,
// so this should be at least 1, even if you're not really implementing programs.
}

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

void AirAudioProcessor::setCurrentProgram (int index)
{
}

const String AirAudioProcessor::getProgramName (int index)
{
return defProgName;
}

void AirAudioProcessor::changeProgramName (int index, const String& newName)
{
}

//==============================================================================
void AirAudioProcessor::prepareToPlay(double sampleRate, int samplesPerBlock)
{
// Use this method as the place to do any pre-playback
// initialisation that you need..

// Initialize filter parameters
filterParams[0] = sampleRate; // Set sample rate
filterParams[1] = 2; // Set order
filterParams[2] = *crossFreq; // Set center freq
filterParams[3] = 1600; // Set bandwidth

// Set filter parameters
lp->setParams(filterParams);
hp->setParams(filterParams);

// Initialize compressor
pCompressor->setSampleRate(sampleRate);
pCompressor->setThreshold(*cThreshold);
pCompressor->setRatio(1.0 + (airRatioAmt * *airAmt));
pCompressor->setAttackRate(0);
pCompressor->setReleaseRate(75);
pCompressor->setMakeupGain(0);
pCompressor->resetSideChain();

// Initialize waveshaper
waveShaper->setAmount(0.0);
// Preallocate buffer memory
hpBuffer.setSize(2, samplesPerBlock);
lpBuffer.setSize(2, samplesPerBlock);
}

void AirAudioProcessor::releaseResources()
{
// When playback stops, you can use this as an opportunity to free up any
// spare memory, etc.
}

#ifndef JucePlugin_PreferredChannelConfigurations
bool AirAudioProcessor::setPreferredBusArrangement (bool isInput, int bus, const AudioChannelSet& preferredSet)
{
// Reject any bus arrangements that are not compatible with your plugin

const int numChannels = preferredSet.size();

#if JucePlugin_IsMidiEffect
if (numChannels != 0)
return false;
#elif JucePlugin_IsSynth
if (isInput || (numChannels != 1 && numChannels != 2))
return false;
#else
if (numChannels != 1 && numChannels != 2)
return false;

if (! AudioProcessor::setPreferredBusArrangement (! isInput, bus, preferredSet))
return false;
#endif

return AudioProcessor::setPreferredBusArrangement (isInput, bus, preferredSet);
}
#endif

void AirAudioProcessor::processBlock (AudioSampleBuffer& buffer, MidiBuffer& midiMessages)
{
const int totalNumInputChannels = getTotalNumInputChannels();
const int totalNumOutputChannels = getTotalNumOutputChannels();
int numSamples = buffer.getNumSamples();
jassert((totalNumInputChannels == 1) || (totalNumInputChannels == 2));
// Clear buffer in case of garbage
for (int i = totalNumInputChannels; i < totalNumOutputChannels; ++i)
buffer.clear (i, 0, numSamples);
// Copy buffer data into cross filter buffers
if(totalNumInputChannels == 2)
{
// If we're running stereo (2,2), copy each channel of the input buffer
hpBuffer.copyFrom(0, 0, buffer, 0, 0, numSamples);
hpBuffer.copyFrom(1, 0, buffer, 1, 0, numSamples);
lpBuffer.copyFrom(0, 0, buffer, 0, 0, numSamples);
lpBuffer.copyFrom(1, 0, buffer, 1, 0, numSamples);
}
else if (totalNumInputChannels == 1)
{
// If we're running mono (1,1) copy input channel into both output channels (workaround)
hpBuffer.copyFrom(0, 0, buffer, 0, 0, numSamples);
hpBuffer.copyFrom(1, 0, buffer, 0, 0, numSamples);
lpBuffer.copyFrom(0, 0, buffer, 0, 0, numSamples);
lpBuffer.copyFrom(1, 0, buffer, 0, 0, numSamples);
}

// Set filter crossover param every block
filterParams[2] = *crossFreq; // Set center freq
lp->setParams(filterParams);
hp->setParams(filterParams);

// Apply the filters to respective buffers
hp->process(numSamples, hpBuffer.getArrayOfWritePointers());
lp->process(numSamples, lpBuffer.getArrayOfWritePointers());

// Set waveshaper params and apply it
waveShaper->setAmount(*airAmt * airSatAmt);
waveShaper->processBlock(hpBuffer);
// Set compressor parameters and apply it
tempRatio = 1.0 + (airRatioAmt * *airAmt);
pCompressor->setThreshold(*cThreshold);
pCompressor->setRatio(tempRatio);
pCompressor->processBlock(hpBuffer);

// Apply post gain to air buffer
hpBuffer.applyGain(*hpGain + (*airAmt * airGainAmt));

// Mix the buffers together and apply Dry/Wet for each channel
for (int channel = 0; channel < totalNumInputChannels; ++channel)
{
// Add lpBuffer to hpBuffer (after processing hpBuffer)
hpBuffer.addFrom(channel, 0, lpBuffer, channel, 0, numSamples);

// WET GAIN
hpBuffer.applyGain(channel, 0, numSamples, *dryWet);
// DRY GAIN
buffer.applyGain(channel, 0, numSamples, 1.0 - *dryWet);

// Add wet signal to buffer
buffer.addFrom(channel, 0, hpBuffer, channel, 0, numSamples);
}

}

//==============================================================================
bool AirAudioProcessor::hasEditor() const
{
return true; // (change this to false if you choose to not supply an editor)
}

AudioProcessorEditor* AirAudioProcessor::createEditor()
{
return new AirAudioProcessorEditor (*this);
}

//==============================================================================
void AirAudioProcessor::getStateInformation (MemoryBlock& destData)
{
// You should use this method to store your parameters in the memory block.
// You could do that either as raw data, or use the XML or ValueTree classes
// as intermediaries to make it easy to save and load complex data.

// Create XML element
XmlElement xml("AIRPLUGINSETTINGS");

// Store values of all paramters, using their param ID as XML attribute
auto params = getParameters();
for (int i = 0; i < params.size(); ++i)
{
if (AudioProcessorParameterWithID* p = dynamic_cast<AudioProcessorParameterWithID*> (params.getUnchecked(i)))
{
xml.setAttribute(p->paramID, p->getValue());
}
}
// Copy the XML to binary to be returned later
copyXmlToBinary(xml, destData);
}

void AirAudioProcessor::setStateInformation (const void* data, int sizeInBytes)
{
// You should use this method to restore your parameters from this memory block,
// whose contents will have been created by the getStateInformation() call.

// Retrieves XML from binary
auto xmlState = std::make_unique<XmlElement>(*getXmlFromBinary(data, sizeInBytes));

// Make sure it's not null
if (xmlState != nullptr)
{
// Make sure it's the right type of XML object
if (xmlState->hasTagName("AIRPLUGINSETTINGS"))
{
// Reload the parameters from XML attributes to param with matching ID
auto params = getParameters();
for (int i = 0; i < params.size(); ++i)
{
if (AudioProcessorParameterWithID* p = dynamic_cast<AudioProcessorParameterWithID*> (params.getUnchecked(i)))
{
p->setValue((float)xmlState->getDoubleAttribute(p->paramID, p->getValue()));
}
}
}
}
}

//==============================================================================
// This creates new instances of the plugin..
AudioProcessor* JUCE_CALLTYPE createPluginFilter()
{
return new AirAudioProcessor();
}

//=============================================================================
// Getters and setters for the dsp params
double AirAudioProcessor::getCrossFreq()
{
return *crossFreq;
}

void AirAudioProcessor::setCrossFreq(double newFreq)
{
*crossFreq = newFreq;
}

double AirAudioProcessor::getDryWet()
{
return *dryWet;
}

void AirAudioProcessor::setDryWet(double newDryWet)
{
*dryWet = newDryWet;
}

double AirAudioProcessor::getThreshold()
{
return *cThreshold;
}

void AirAudioProcessor::setThreshold(double newThreshold)
{
*cThreshold = newThreshold;
}

double AirAudioProcessor::getRatio()
{
return cRatio;
}

void AirAudioProcessor::updateRatio()
{
cRatio = 1 + (airRatioAmt * *airAmt);
}

double AirAudioProcessor::getHpGain()
{
return *hpGain;
}

void AirAudioProcessor::setHpGain(double newHpGain)
{
*hpGain = newHpGain;
}

double AirAudioProcessor::getHpPreGain()
{
return hpPreGain;
}

void AirAudioProcessor::setHpPreGain(double newHpPreGain)
{
hpPreGain = newHpPreGain;
}

double AirAudioProcessor::getSatAmt()
{
return satAmt;
}

void AirAudioProcessor::setSatAmt(double newSatAmt)
{
satAmt = newSatAmt;
}

double AirAudioProcessor::getAirRatioAmt()
{
return airRatioAmt;
}

void AirAudioProcessor::setAirRatioAmt(double newAirRatioAmt)
{
airRatioAmt = newAirRatioAmt;
}

double AirAudioProcessor::getAirGainAmt()
{
return airGainAmt;
}

void AirAudioProcessor::setAirGainAmt(double newAirGainAmt)
{
airGainAmt = newAirGainAmt;
}

double AirAudioProcessor::getAirSatAmt()
{
return airSatAmt;
}

void AirAudioProcessor::setAirSatAmt(double newAirSatAmt)
{
airSatAmt = newAirSatAmt;
}

double AirAudioProcessor::getAirAmt()
{
return *airAmt;
}

void AirAudioProcessor::setAirAmt(double newAirAmt)
{
*airAmt = newAirAmt;
}

double AirAudioProcessor::getTempGainReduction()
{
return pCompressor->getTempGainReduction();
}

+ 143
- 0
ports-juce6/roth-air/PluginProcessor.h View File

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

Plugin processor
================
A Juce class containing the Roth-AIR plugin parameters and audio processing instructions

By Daniel Rothmann

Provided under GNU General Public license:
http://www.gnu.org/licenses/

------------------------------------------------------------------------------
*/

#ifndef PLUGINPROCESSOR_H_INCLUDED
#define PLUGINPROCESSOR_H_INCLUDED

#include "JuceHeader.h"
#include "Compressor.h"
#include "DspFilters/Dsp.h"
#include "WaveShaper.h"

//==============================================================================
class AirAudioProcessor : public AudioProcessor
{
public:
//==============================================================================
AirAudioProcessor();
~AirAudioProcessor();

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

#ifndef JucePlugin_PreferredChannelConfigurations
bool setPreferredBusArrangement (bool isInput, int bus, const AudioChannelSet& preferredSet) override;
#endif

void processBlock (AudioSampleBuffer&, MidiBuffer&) override;

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

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

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

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

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

//=============================================================================
// Declare some getters and setters
double getCrossFreq();
void setCrossFreq(double newFreq);

double getDryWet();
void setDryWet(double newDryWet);

double getThreshold();
void setThreshold(double newThreshold);

double getRatio();
void updateRatio();

double getHpGain();
void setHpGain(double newHpGain);

double getHpPreGain();
void setHpPreGain(double newHpPreGain);

double getSatAmt();
void setSatAmt(double newSatAmt);

double getAirRatioAmt();
void setAirRatioAmt(double newAirRatioAmt);

double getAirGainAmt();
void setAirGainAmt(double newAirGainAmt);

double getAirSatAmt();
void setAirSatAmt(double newAirSatAmt);

double getAirAmt();
void setAirAmt(double newAirAmt);

double getTempGainReduction();

// Declare automatable parameters that host will understand
AudioParameterFloat* crossFreq;
AudioParameterFloat* dryWet;
AudioParameterFloat* cThreshold;
AudioParameterFloat* hpGain;
AudioParameterFloat* airAmt;

private:
// Declare buffers
AudioSampleBuffer hpBuffer;
AudioSampleBuffer lpBuffer;

// Declare filters
std::unique_ptr<Dsp::Filter> lp;
std::unique_ptr<Dsp::Filter> hp;
Dsp::Params filterParams;

// Declare compressor
std::unique_ptr<Compressor> pCompressor;

// Declare waveshaper
std::unique_ptr<WaveShaper> waveShaper;

// Declare parameters
double cRatio = 1.0;
double hpPreGain = 0;
double satAmt = 0.0;

double airRatioAmt = 3.0;
double airGainAmt = 0.0;
double airSatAmt = 0.5;

double tempRatio;

// Declare program name
String defProgName = "Roth-AIR";

//==============================================================================
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AirAudioProcessor)
};


#endif // PLUGINPROCESSOR_H_INCLUDED

+ 8
- 0
ports-juce6/roth-air/README.md View File

@@ -0,0 +1,8 @@
# Roth-AIR
Roth-AIR is a mixing tool for easily adding airy, crispy presence to your audio.

This is achieved by a combination of multiband compression and gentle saturation of the highs. It enables for a stronger, more consistent presence of high frequency material and works particularly well with vocals, synths and strings.

The process is made easy by a simple user interface, automatic makeup gain and a combined function "AIR" knob.

Current version: 1.1.0

+ 312
- 0
ports-juce6/roth-air/SideChain.cpp View File

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

SideChain (Compressor)
==========
A simple feed forward compressor for use in AIR plugin - this class contains side chain calculation

A simplified implementation of Martin Zuther's "Squeezer" with some modifications
https://github.com/mzuther/Squeezer

-----------------------------------------------------*/

#include "SideChain.h"

SideChain::SideChain(int nSampleRate)
{
// Convert sample rate to double
dSampleRate = (double) nSampleRate;

// Initialize variables
setThreshold(0.0);
setRatio(1.0);

// RMS smoothing for incoming values
setDetectorRmsFilter(5.0);

// Set sidechain speeds (ms)
setAttackRate(1);
setReleaseRate(60);

reset();
}

SideChain::~SideChain()
{
}

void SideChain::reset()
/* Reset all relevant variables.
return value: none
*/
{
dGainReduction = 0.0;
dGainCompensation = 0.0;
dDetectorOutputLevelSquared = 0.0;

dCrestFactorAutoGain = 20.0;
}

double SideChain::getDetectorRmsFilter()
/* Get current detector RMS filter rate.

return value (double): returns current detector RMS filter rate*/
{
return dDetectorRateMs;
}

void SideChain::setDetectorRmsFilter(double dDetectorRateMsNew)
/* Set new detector RMS filter rate.
dDetectorRateMsNew (double): new detector RMS filter rate; set to 0.0 to disable RMS

return value: none*/
{
if (dDetectorRateMsNew <= 0.0)
{
dDetectorRateMs = 0.0;
dDetectorCoefficient = 0.0;
}
else
{
dDetectorRateMs = dDetectorRateMsNew;
double dDetectorRateSeconds = dDetectorRateMs / 1000.0;

// Apply logarithmic envelope to the coeffecient
dDetectorCoefficient = exp(log(0.10) / (dDetectorRateSeconds * dSampleRate));
}
}

double SideChain::getThreshold()
/* Get current threshold.

return value (double): returns current threshold in dB*/
{
return dThreshold;
}

void SideChain::setThreshold(double dThresholdNew)
/* Set new threshold.

dThresholdNew (double): new threshold in dB

return value: none
*/
{
dThreshold = dThresholdNew;
dGainCompensation = queryGainComputer(dCrestFactorAutoGain) / 2.0;
}

double SideChain::getRatio()
/* Get current compression ratio.
return value (double): returns current compression ratio*/
{
return 1.0 / (1.0 - dRatioInternal);
}

void SideChain::setRatio(double dRatioNew)
/* Set new compression ratio.

dRatioNew (double): new compression ratio

return value: none*/
{
dRatioInternal = 1.0 - (1.0 / dRatioNew);
dGainCompensation = queryGainComputer(dCrestFactorAutoGain) / 2.0;
}

int SideChain::getAttackRate()
/* Get attack rate.

return value (integer): returns current attack rate (ms)*/
{
return nAttackRate;
}

void SideChain::setAttackRate(int nAttackRateNew)
/* Set new attack rate.

nAttackRateNew (integer): new attack rate in ms

return value: none
*/
{
nAttackRate = nAttackRateNew;

if (nAttackRate == 0)
{
dAttackCoefficient = 0.0;
}
else
{
double dAttackRateSeconds = nAttackRate / 1000.0;

// Apply logarithmic envelope to the coeffecient
dAttackCoefficient = exp(log(0.10) / (dAttackRateSeconds * dSampleRate));
}
}

int SideChain::getReleaseRate()
/* Get release rate.

return value (integer): returns current release rate (ms)*/
{
return nReleaseRate;
}

void SideChain::setReleaseRate(int nReleaseRateNew)
/* Set new release rate.

nReleaseRateNew (integer): new release rate in ms

return value: none
*/
{
nReleaseRate = nReleaseRateNew;

if (nReleaseRate == 0)
{
dReleaseCoefficient = 0.0;
}
else
{
double dReleaseRateSeconds = nReleaseRate / 1000.0;

// Apply logarithmic envelope to the coeffecient
dReleaseCoefficient = exp(log(0.10) / (dReleaseRateSeconds * dSampleRate));
}
}

double SideChain::getGainReduction()
/* Get current gain reduction.

return value (double): returns current gain reduction in dB*/
{
// Return gain reduction - gain compensation (edited script)
return dGainReduction - dGainCompensation;
}

double SideChain::queryGainComputer(double dInputLevel)
/* Calculate gain reduction and envs from input lvl

dInputLevel (double): current input level in dB

return value: calculated gain reduction in dB*/
{
// Calculate how far input is above threshold
double dAboveThreshold = dInputLevel - dThreshold;

// If level is under threshold return 0, otherwise return amt above threshold times the ratio
if (dInputLevel <= dThreshold)
{
return 0.0;
}
else
{
return dAboveThreshold * dRatioInternal;
}
}

void SideChain::processSample(double dInputLevel)
/* Process a single sample value

dInputLevel (double): current audio sample value in dB

return value: current gain rection in dB*/
{
// Send input level to gain computer
dGainReductionIdeal = queryGainComputer(dInputLevel);

// Filter calculated gain reductino through level detection filter
double dGainReductionNew = applyLevelDetectionFilter(dGainReductionIdeal);

// Send input from gain computer to level detector (smooth branching hard coded)
applyDetectorSmoothDecoupled(dGainReductionNew);
}

double SideChain::applyLevelDetectionFilter(double dDetectorInputLevel)
{
// Bypass RMS sensing if rate is <= 0
if (dDetectorRateMs <= 0.0)
{
return dDetectorInputLevel;
}
else
{
// Do some root mean square magic
double dDetectorInputLevelSquared = dDetectorInputLevel * dDetectorInputLevel;
double dDetectorOutputLevelSquaredOld = dDetectorOutputLevelSquared;

dDetectorOutputLevelSquared = (dDetectorCoefficient * dDetectorOutputLevelSquaredOld) + (1.0 - dDetectorCoefficient) * dDetectorInputLevelSquared;

double dDetectorOutputLevel = sqrt(dDetectorOutputLevelSquared);
return dDetectorOutputLevel;
}
}

void SideChain::applyDetectorSmoothDecoupled(double dGainReductionNew)
/* Calculate smooth decoupled detector (s-curve)

dGainReductionNew (double): calculated gain reduction in dB

return value: none*/
{
// apply release envelope
if (dReleaseCoefficient == 0.0)
{
dGainReductionIntermediate = dGainReductionNew;
}
else
{
double dGainReductionIntermediateOld = dGainReductionIntermediate;
dGainReductionIntermediate = (dReleaseCoefficient * dGainReductionIntermediateOld) + (1.0 - dReleaseCoefficient) * dGainReductionNew;

// Maximally fast peak detection
if (dGainReductionNew > dGainReductionIntermediate)
{
dGainReductionIntermediate = dGainReductionNew;
}
}

// apply attack envelope
if (dAttackCoefficient == 0.0)
{
dGainReduction = dGainReductionIntermediate;
}
else
{
double dGainReductionOld = dGainReduction;
dGainReduction = (dAttackCoefficient * dGainReductionOld) + (1.0 - dAttackCoefficient) * dGainReductionIntermediate;
}
}

double SideChain::lvltodb(double dLevel)
/* Convert level from linear scale to dB

dLevel (double): audio level

return value (double): given level in dB*/
{
double dDecibels = 20.0 * log10(dLevel);

return dDecibels;
}

double SideChain::dbtolvl(double dDecibels)
/* Convert level from dB to linear scale

dDecibels (double): audio level in dB

return value (double): given level in linear scale*/
{
double dLevel = pow(10.0, dDecibels / 20.0);
return dLevel;
}

double SideChain::getSampleRate()
{
return dSampleRate;
}

void SideChain::setSampleRate(double newSampleRate)
{
dSampleRate = newSampleRate;
}

+ 81
- 0
ports-juce6/roth-air/SideChain.h View File

@@ -0,0 +1,81 @@
/*---------------------------------------------------
SideChain (Compressor)
==========
A simple feed forward compressor for use in AIR plugin - this class contains side chain calculation
A simplified implementation of Martin Zuther's "Squeezer" with some modifications
https://github.com/mzuther/Squeezer
-----------------------------------------------------*/

#ifndef __SIDECHAIN_H__
#define __SIDECHAIN_H__

#include "JuceHeader.h"

class SideChain
{
public:
SideChain(int nSampleRate);
~SideChain();

void reset();

double getDetectorRmsFilter();
void setDetectorRmsFilter(double dDetectorRateMsNew);

double getThreshold();
void setThreshold(double dThresholdNew);

double getRatio();
void setRatio(double dRatioNew);

int getAttackRate();
void setAttackRate(int nAttackRateNew);

int getReleaseRate();
void setReleaseRate(int nReleaseRateNew);

double getGainReduction();

void processSample(double dSampleValue);

static double lvltodb(double dLevel);
static double dbtolvl(double dDecibels);
double getSampleRate();
void setSampleRate(double newSampleRate);

private:
// JUCE_LEAK_DETECTOR(SideChain);

double dSampleRate;
double dCrestFactorAutoGain;
double dGainReduction;
double dGainReductionIdeal = 0.0;
double dGainReductionIntermediate = 0.0;
double dGainCompensation;

double dDetectorCoefficient;
double dDetectorOutputLevelSquared;
double dDetectorRateMs;
int nDetectorType;
double dThreshold;
double dRatioInternal;

int nAttackRate;
double dAttackCoefficient = 0.0;

int nReleaseRate;
double dReleaseCoefficient = 0.0;

double queryGainComputer(double dInputLevel);
double applyLevelDetectionFilter(double dDetectorInputLevel);
// void applyDetectorLinear(double dGainRectionNew);
void applyDetectorSmoothDecoupled(double dGainReductionNew);
// void applyDetectorSmoothBranching(double dGainReductionNew);
};

#endif //__SIDECHAIN_H__

+ 57
- 0
ports-juce6/roth-air/WaveShaper.cpp View File

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

Simple waveshaper
==========
A simple harmonic waveshaper for use in Roth-AIR
By Daniel Rothmann

Provided under GNU General Public license:
http://www.gnu.org/licenses/

------------------------------------------------------------------------------
*/

#include "WaveShaper.h"

//====================================================

WaveShaper::WaveShaper(int channels)
{
amount = 0;
nChannels = channels;
}

double WaveShaper::getAmount()
{
return amount;
}

void WaveShaper::setAmount(double newAmount)
{
amount = 2 * newAmount / (1 - newAmount);
}

void WaveShaper::processBlock(AudioBuffer<float> &buffer)
{
int nNumSamples = buffer.getNumSamples();

// Loop through samples
for (int nSample = 0; nSample < nNumSamples; ++nSample)
{
// Loop through channels
for (int nChannel = 0; nChannel < nChannels; ++nChannel)
{
// Input sample (in)
float in = buffer.getSample(nChannel, nSample);
// Output sample (out)
float out = 0.0;

// Output sample becomes waveshaped in
out = (1.0 + amount) * in / (1.0 + amount * abs(in));

// Change sample value in buffer
buffer.setSample(nChannel, nSample, out);
}
}
}

+ 37
- 0
ports-juce6/roth-air/WaveShaper.h View File

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

Simple waveshaper
================
A simple harmonic waveshaper for use in Roth-AIR
By Daniel Rothmann

Provided under GNU General Public license:
http://www.gnu.org/licenses/

------------------------------------------------------------------------------
*/

#ifndef WAVESHAPER_H_INCLUDED
#define WAVESHAPER_H_INCLUDED

#include "JuceHeader.h"

class WaveShaper
{
public:
WaveShaper(int channels);

double getAmount();
void setAmount(double newAmount);

void processBlock(AudioBuffer<float> &buffer);

private:
double amount;
int nChannels;
};



#endif // WAVESHAPER_H_INCLUDED

+ 21
- 0
ports-juce6/roth-air/meson.build View File

@@ -0,0 +1,21 @@
###############################################################################

plugin_srcs = files([
'BinaryData.cpp',
'Compressor.cpp',
'PluginEditor.cpp',
'PluginProcessor.cpp',
'SideChain.cpp',
'WaveShaper.cpp',
'DspFilters/source/Bessel.cpp',
'DspFilters/source/Biquad.cpp',
'DspFilters/source/Cascade.cpp',
'DspFilters/source/Filter.cpp',
'DspFilters/source/Param.cpp',
'DspFilters/source/PoleFilter.cpp',
'DspFilters/source/RootFinder.cpp',
])

plugin_name = 'Roth-Air'

###############################################################################

Loading…
Cancel
Save