Browse Source

Add ReFine plugin

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

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

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

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

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

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

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


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

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

private:

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

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

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

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

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


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

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

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

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

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

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

rmsVals.push(rmsVal);
return true;
}

return false;
}

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

const int ovSize = int(updateTime * sampleRate);

jassert(ovSize > 100);

int idx = 0;

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

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

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

rmsVals.push(rmsVal);
}
}
}

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

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

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

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

return true;
}

return false;
}

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

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

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

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

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

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

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

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

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

return false;
}

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

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

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

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

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

clear();
}
}

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

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

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

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

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

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

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

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

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

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

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

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

private:

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

juce::CriticalSection processLock;

JUCE_DECLARE_NON_COPYABLE (RmsEnvelope)
};


class Analyzer
{
public:

struct Data;

Analyzer();

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

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

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

private:

void processFFT();

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

int fftIndex;

int fftBlockSize;
int numBins;

double sampleRate;
};


#endif // __ANALYZER_H__

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


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

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

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

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

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

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

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

return rms / buffer.getSize();
}

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

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

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

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

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

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

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

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

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

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

data[index] = x;

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

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

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

data[index] = x;

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

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

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

data[index] = x;

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

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

data[index] = x;

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

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

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

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

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

#include "JuceHeader.h"

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

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

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

return true;
}

return false;
}

int getSize() const
{
return size;
}

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

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

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

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

return ret;
}

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

if (idx < 0)
idx += size;

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

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

private:

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

class RmsBuffer
{
public:
RmsBuffer (int initSize);

void clear();

double process (double in);

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

void setSize (int newSize);

int getSize();

double getRms();


private:

double rms;
CircularBuffer<double> buffer;
};


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

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


private:

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

int index;

JUCE_DECLARE_NON_COPYABLE(RmsLevel)
};


#endif // BUFFERS_H_INCLUDED

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

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

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

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

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

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

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

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

double a0 = 1;

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

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


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

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

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

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

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

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

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

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

return (float) y;
}

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

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

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

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

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

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

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

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

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

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

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

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

#include "JuceHeader.h"

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

kNumFilters
};
}

struct BiquadCoefficients
{
BiquadCoefficients();

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

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

class StaticBiquad
{
public:

StaticBiquad();

void clear();

void setSampleRate (double newSampleRate);

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

float process (float in);

void processBlock (float* in, int numSamples);

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

float getLast (bool left);

private:

double sampleRate;

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

BiquadCoefficients coeff;

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

class SimpleNoiseGen
{
public:

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

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


#endif // DSPSTUFF_H_INCLUDED

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

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


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

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

addAndMakeVisible(visualisation);

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

ReFinedAudioProcessorEditor::~ReFinedAudioProcessorEditor()
{
}

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

}

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

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

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

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

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

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

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

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

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

void timerCallback() override;

private:

ReFinedAudioProcessor& processor;

Image background;

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

Visualisation visualisation;

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


#endif // PLUGINEDITOR_H_INCLUDED

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

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

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

ReFinedAudioProcessor::~ReFinedAudioProcessor()
{
}

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

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

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

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

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

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

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

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

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

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

void ReFinedAudioProcessor::releaseResources()
{
}

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

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

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

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

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

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

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

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

copyXmlToBinary(xml, destData);
}

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

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

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

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

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

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

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

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

void processBlock (AudioSampleBuffer&, MidiBuffer&) override;

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

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

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

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

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

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

ScopedPointer<AudioProcessorValueTreeState> parameters;

private:

RefineDsp dsp;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ReFinedAudioProcessor)
};


#endif // PLUGINPROCESSOR_H_INCLUDED

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

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

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

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

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

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

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

#include "JuceHeader.h"

class RefinedSlider : public Slider
{
public:

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

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

float getVuValue() const
{
return vuValue;
}

const Image sliderImage;
const Image vuImage;

private:

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

class X2Button : public Button
{
public:

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

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

private:

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

class RefineLookAndFeel : public LookAndFeel_V3
{
public:

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

private:

};



#endif // REFINELOOKANDFEEL_H_INCLUDED

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

delayL.processBlock(dataL, numSamples);

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

{
ScopedLock lock(processLock);

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

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

if (dataR == nullptr)
dataR = dataL;

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

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

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

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

double r300 = rms300.process(x);

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

double r5 = rms5.process(x);

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

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

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

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

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

colorProc.add(transient, nonTransient, level);

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


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

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

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

return rms.getData(d);
}




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

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

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

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

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

void clear()
{
value = 0;
}

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

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

if (x > value)
value = x;
}

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

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

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

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

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

private:

double attack;
double release;
double value;

};



class RefineDsp
{
public:
RefineDsp();

void clear();

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

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

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

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

private:

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

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

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

const float sum = transient + nonTransient + level;

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

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

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

float transient;
float nonTransient;
float level;
};


double sampleRate;

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

float transient;
float nonTransient;
float level;

SimpleNoiseGen noise;

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

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

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

LevelHold trSmooth;

LevelHold levelHold;

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

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

juce::CriticalSection processLock;
};

#endif // SEPDSP_H_INCLUDED

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Visualisation::~Visualisation()
{
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

private:

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

float minMag;
float maxMag;

JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Visualisation)
};


#endif // VISUALISATION_H_INCLUDED

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

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

Array.h
By Laurent de Soras

--- Legal stuff ---

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

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



#if ! defined (ffft_Array_HEADER_INCLUDED)
#define ffft_Array_HEADER_INCLUDED

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



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



namespace ffft
{



template <class T, long LEN>
class Array
{

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

public:

typedef T DataType;

Array ();

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

static inline long
size ();



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

protected:



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

private:

DataType _data_arr [LEN];



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

private:

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

}; // class Array