Browse Source

Update obxd (discoDSP version)

tags/2018-04-16
falkTX 7 years ago
parent
commit
a1d4957cf7
39 changed files with 9822 additions and 21837 deletions
  1. +0
    -0
      ports/obxd/source/Engine/APInterpolator.h
  2. +7
    -2
      ports/obxd/source/Engine/AdsrEnvelope.h
  3. +22
    -8
      ports/obxd/source/Engine/AudioUtils.h
  4. +9
    -4
      ports/obxd/source/Engine/BlepData.h
  5. +40
    -26
      ports/obxd/source/Engine/Decimator.h
  6. +23
    -61
      ports/obxd/source/Engine/DelayLine.h
  7. +83
    -53
      ports/obxd/source/Engine/Filter.h
  8. +88
    -3
      ports/obxd/source/Engine/Lfo.h
  9. +97
    -68
      ports/obxd/source/Engine/Motherboard.h
  10. +0
    -0
      ports/obxd/source/Engine/ObxdBank.h
  11. +60
    -43
      ports/obxd/source/Engine/ObxdOscillatorB.h
  12. +108
    -67
      ports/obxd/source/Engine/ObxdVoice.h
  13. +2
    -2
      ports/obxd/source/Engine/ParamSmoother.h
  14. +13
    -7
      ports/obxd/source/Engine/Params.h
  15. +12
    -3
      ports/obxd/source/Engine/ParamsEnum.h
  16. +30
    -39
      ports/obxd/source/Engine/PulseOsc.h
  17. +29
    -36
      ports/obxd/source/Engine/SawOsc.h
  18. +186
    -136
      ports/obxd/source/Engine/SynthEngine.h
  19. +38
    -50
      ports/obxd/source/Engine/TriangleOsc.h
  20. +7
    -8
      ports/obxd/source/Engine/VoiceQueue.h
  21. +0
    -0
      ports/obxd/source/Engine/midiMap.h
  22. +7884
    -0
      ports/obxd/source/Gui/BinaryData.cpp
  23. +41
    -0
      ports/obxd/source/Gui/BinaryData.h
  24. +4
    -4
      ports/obxd/source/Gui/ButtonList.h
  25. +0
    -0
      ports/obxd/source/Gui/Knob.h
  26. +0
    -0
      ports/obxd/source/Gui/TooglableButton.h
  27. +0
    -20771
      ports/obxd/source/Gui/res.cpp
  28. +0
    -69
      ports/obxd/source/Gui/res.h
  29. BIN
      ports/obxd/source/Images/button.png
  30. BIN
      ports/obxd/source/Images/knoblsd.png
  31. BIN
      ports/obxd/source/Images/knobssd.png
  32. BIN
      ports/obxd/source/Images/legato.png
  33. BIN
      ports/obxd/source/Images/main.png
  34. BIN
      ports/obxd/source/Images/voices.png
  35. +1
    -0
      ports/obxd/source/JuceHeader.h
  36. +427
    -140
      ports/obxd/source/PluginEditor.cpp
  37. +25
    -30
      ports/obxd/source/PluginEditor.h
  38. +439
    -174
      ports/obxd/source/PluginProcessor.cpp
  39. +147
    -33
      ports/obxd/source/PluginProcessor.h

+ 0
- 0
ports/obxd/source/Engine/APInterpolator.h View File


+ 7
- 2
ports/obxd/source/Engine/AdsrEnvelope.h View File

@@ -101,6 +101,10 @@ public:
coef = (float)((log(0.00001) - log(Value+0.0001)) / (SampleRate * (release) / 1000));
state = 4;
}
inline bool isActive()
{
return state!=5;
}
inline float processSample()
{
switch (state)
@@ -132,8 +136,9 @@ public:
case 3: Value = jmin(sustain, 0.9f);
break;
case 4:
// if (Value > 10e-6)
if (Value > 20e-6)
Value = Value + Value * coef + dc;
else state = 5;
break;
case 5:
Value = 0.0f;
@@ -142,4 +147,4 @@ public:
return Value;
}

};
};

+ 22
- 8
ports/obxd/source/Engine/AudioUtils.h View File

@@ -25,7 +25,6 @@

#include "SynthEngine.h"


const float sq2_12 = 1.0594630943592953f;

const float dc = 1e-18;
@@ -33,15 +32,26 @@ const float ln2 = 0.69314718056f;
const float mult = ln2 / 12.0;
inline static float getPitch(float index)
{
return (440* expf( mult*index));
};
//Lookup table is not that effective compared to SSE exp
//SSE should be on

inline static float nlp(float& state,float inp,float cutoff,float sr)
{
cutoff =atan((cutoff / (sr)))/juce::float_Pi;
state = state + (inp - state) * cutoff +dc;
return state;
//const int mulres = 2;
//const int lowerBound = -94;
//const int upperBound = 94;
//const int lutlen = (upperBound-lowerBound)*2;
return 440 * expf(mult * index);
//static const float lut [lutlen]={1.929,1.986,2.044,2.104,2.165,2.229,2.294,2.361,2.431,2.502,2.575,2.651,2.728,2.808,2.891,2.975,3.062,3.152,3.245,3.340,3.437,3.538,3.642,3.749,3.858,3.972,4.088,4.208,4.331,4.458,4.589,4.723,4.861,5.004,5.150,5.301,5.457,5.617,5.781,5.951,6.125,6.304,6.489,6.679,6.875,7.076,7.284,7.497,7.717,7.943,8.176,8.415,8.662,8.916,9.177,9.446,9.723,10.008,10.301,10.603,10.913,11.233,11.562,11.901,12.250,12.609,12.978,13.359,13.750,14.153,14.568,14.994,15.434,15.886,16.352,16.831,17.324,17.832,18.354,18.892,19.445,20.015,20.602,21.205,21.827,22.466,23.125,23.802,24.500,25.218,25.957,26.717,27.500,28.306,29.135,29.989,30.868,31.772,32.703,33.661,34.648,35.663,36.708,37.784,38.891,40.030,41.203,42.411,43.654,44.933,46.249,47.605,48.999,50.435,51.913,53.434,55.000,56.612,58.270,59.978,61.735,63.544,65.406,67.323,69.296,71.326,73.416,75.567,77.782,80.061,82.407,84.822,87.307,89.865,92.499,95.209,97.999,100.870,103.826,106.869,110.000,113.223,116.541,119.956,123.471,127.089,130.813,134.646,138.591,142.652,146.832,151.135,155.563,160.122,164.814,169.643,174.614,179.731,184.997,190.418,195.998,201.741,207.652,213.737,220.000,226.446,233.082,239.912,246.942,254.178,261.626,269.292,277.183,285.305,293.665,302.270,311.127,320.244,329.628,339.286,349.228,359.461,369.994,380.836,391.995,403.482,415.305,427.474,440.000,452.893,466.164,479.823,493.883,508.355,523.251,538.584,554.365,570.609,587.330,604.540,622.254,640.487,659.255,678.573,698.456,718.923,739.989,761.672,783.991,806.964,830.609,854.948,880.000,905.786,932.328,959.647,987.767,1016.710,1046.502,1077.167,1108.731,1141.219,1174.659,1209.079,1244.508,1280.975,1318.510,1357.146,1396.913,1437.846,1479.978,1523.344,1567.982,1613.927,1661.219,1709.896,1760.000,1811.572,1864.655,1919.294,1975.533,2033.421,2093.005,2154.334,2217.461,2282.438,2349.318,2418.158,2489.016,2561.950,2637.020,2714.291,2793.826,2875.691,2959.955,3046.689,3135.964,3227.854,3322.438,3419.792,3520.000,3623.144,3729.310,3838.587,3951.066,4066.842,4186.009,4308.668,4434.922,4564.875,4698.636,4836.317,4978.032,5123.899,5274.041,5428.582,5587.652,5751.382,5919.911,6093.377,6271.927,6455.709,6644.875,6839.585,7040.000,7246.288,7458.620,7677.174,7902.133,8133.683,8372.018,8617.337,8869.844,9129.751,9397.273,9672.634,9956.064,10247.798,10548.082,10857.164,11175.304,11502.765,11839.822,12186.755,12543.854,12911.417,13289.750,13679.170,14080.000,14492.576,14917.241,15354.349,15804.266,16267.366,16744.036,17234.674,17739.689,18259.501,18794.545,19345.268,19912.127,20495.597,21096.164,21714.329,22350.607,23005.530,23679.643,24373.510,25087.708,25822.834,26579.501,27358.340,28160.000,28985.151,29834.481,30708.698,31608.532,32534.732,33488.073,34469.348,35479.377,36519.002,37589.091,38690.535,39824.254,40991.194,42192.328,43428.657,44701.214,46011.060,47359.287,48747.020,50175.416,51645.668,53159.002,54716.680,56320.001,57970.303,59668.962,61417.396,63217.063,65069.465,66976.146,68938.697,70958.755,73038.005,75178.182,77381.071,79648.509,81982.388,84384.656,86857.315,89402.429,92022.120,94718.574,97494.040};
//if(index > 92.0)
// return lut[lutlen-1];
//if(index < -94.0)
// return lut[0];
//index = (index - lowerBound)*mulres;
//int mi = floor(index);
//float ofs = index-mi;
//
// return lut[mi] + (lut[mi+1] - lut[mi]) * ofs;
};

inline static float tptlpupw(float & state , float inp , float cutoff , float srInv)
{
cutoff = (cutoff * srInv)*juce::float_Pi;
@@ -50,6 +60,7 @@ inline static float tptlpupw(float & state , float inp , float cutoff , float sr
state = res + v;
return res;
}

inline static float tptlp(float& state,float inp,float cutoff,float srInv)
{
cutoff = tan(cutoff * (srInv)* (juce::float_Pi)) ;
@@ -58,6 +69,7 @@ inline static float tptlp(float& state,float inp,float cutoff,float srInv)
state = res + v;
return res;
};

inline static float tptpc(float& state,float inp,float cutoff)
{
double v = (inp - state) * cutoff / (1 + cutoff);
@@ -65,10 +77,12 @@ inline static float tptpc(float& state,float inp,float cutoff)
state = res + v;
return res;
}

inline static float linsc(float param,const float min,const float max)
{
return (param) * (max - min) + min;
}

inline static float logsc(float param, const float min,const float max,const float rolloff = 19.0f)
{
return ((expf(param * logf(rolloff+1)) - 1.0f) / (rolloff)) * (max-min) + min;


+ 9
- 4
ports/obxd/source/Engine/BlepData.h
File diff suppressed because it is too large
View File


+ 40
- 26
ports/obxd/source/Engine/Decimator.h View File

@@ -5,39 +5,53 @@
class Decimator17
{
private:
const float h0,h1,h3,h5,h7,h9,h11,h13,h15,h17;
float R1,R2,R3,R4,R5,R6,R7,R8,R9,R10,R11,R12,R13,R14,R15,R16,R17;
public:
Decimator17()
: h0(0.5)
, h1(0.314356238)
, h3(-0.0947515890)
, h5(0.0463142134)
, h7(-0.0240881704)
, h9(0.0120250406)
, h11(-0.00543170841)
, h13(0.00207426259)
, h15(-0.000572688237)
, h17(5.18944944e-005)
{
R1=R2=R3=R4=R5=R6=R7=R8=R9=R10=R11=R12=R13=R14=R15=R16=R17;
R1=R2=R3=R4=R5=R6=R7=R8=R9=R10=R11=R12=R13=R14=R15=R16=R17=0;
}
float Calc(const float x0,const float x1)
{
//float h17x0 = h17*x0;
//float h15x0 = h15 * x0;
//float h13x0 = h13 * x0;


//float h11x0= h11 *x0;


// float h9x0=h9*x0;
// float h7x0=h7*x0;
// float h5x0=h5*x0;
// float h3x0=h3*x0;
// float h1x0=h1*x0;
//float R18=R7+h17x0;
//R17 = R16 + h15x0;
// R9=R8+h7x0;
// R8=R7+h5x0;
// R7=R6+h3x0;
// R6=R5+h1x0;
// R5=R4+h1x0+h0*x1;
//R4=R3+h3x0;
// R3=R2+h5x0;
// R2=R1+h7x0;
// R1=h9x0;
return R10;
float h17x0 = h17 *x0;
float h15x0 = h15 *x0;
float h13x0 = h13 *x0;
float h11x0= h11 *x0;
float h9x0=h9*x0;
float h7x0=h7*x0;
float h5x0=h5*x0;
float h3x0=h3*x0;
float h1x0=h1*x0;
float R18=R17+h17x0;
R17 = R16 + h15x0;
R16 = R15 + h13x0;
R15 = R14 + h11x0;
R14 = R13 + h9x0;
R13 = R12 + h7x0;
R12 = R11 + h5x0;
R11 = R10 + h3x0;
R10 = R9 + h1x0;
R9 = R8 + h1x0 + h0*x1;
R8 = R7 + h3x0;
R7 = R6 + h5x0;
R6 = R5 + h7x0;
R5 = R4 + h9x0;
R4 = R3 + h11x0;
R3 = R2 + h13x0;
R2 = R1 + h15x0;
R1 = h17x0;
return R18;
}
};
class Decimator9


+ 23
- 61
ports/obxd/source/Engine/DelayLine.h View File

@@ -23,87 +23,49 @@
*/
#pragma once
#include "SynthEngine.h"
class DelayLine
//Always feed first then get delayed sample!
#define DEMAX 64
template<unsigned int DM> class DelayLine
{
private:
float* dl;
float dl[DEMAX];
int iidx;
int maxc;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(DelayLine)
public:
DelayLine()
DelayLine()
{
dl = NULL;
iidx = 0;
maxc=0;
zeromem(dl,sizeof(float)*DEMAX);
//jassert(DM > DMAX);
}
DelayLine(int count)
{
iidx=0;
maxc=count;
dl = new float[maxc];
for(int i = 0 ; i < maxc;i++)
dl[i]=0;
}
~DelayLine()
{
delete dl;
}
inline void feedDelay(float sm)
inline float feedReturn(float sm)
{
dl[iidx] = sm;
iidx++;
if(iidx >= (maxc))
iidx-=(maxc);
iidx--;
iidx=(iidx&(DEMAX-1));
return dl[(iidx + DM)&(DEMAX-1)];
}
inline float getDelayedSample()
inline void fillZeroes()
{
int idx;
idx = iidx-(maxc);
if(idx <0)
idx+=maxc;
return dl[idx];
zeromem(dl,DEMAX*sizeof(float));
}
};
class DelayLineBoolean
template<unsigned int DM> class DelayLineBoolean
{
private:
bool* dl;
bool dl[DEMAX];
int iidx;
int maxc;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(DelayLineBoolean)
public:
DelayLineBoolean()
DelayLineBoolean()
{
dl = NULL;
iidx = 0;
maxc=0;
}
DelayLineBoolean(int count)
{
iidx=0;
maxc=count;
dl = new bool[maxc];
for(int i = 0 ; i < maxc;i++)
dl[i]=0;
zeromem(dl,sizeof(bool)*DEMAX);
}
~DelayLineBoolean()
{
delete dl;
}
inline void feedDelay(bool sm)
inline float feedReturn(bool sm)
{
dl[iidx] = sm;
iidx++;
if(iidx >= (maxc))
iidx-=(maxc);
}
inline bool getDelayedSample()
{
int idx;
idx = iidx-(maxc);
if(idx <0)
idx+=maxc;
return dl[idx];
iidx--;
iidx=(iidx&(DEMAX-1));
return dl[(iidx + DM)&(DEMAX-1)];
}
};

};

+ 83
- 53
ports/obxd/source/Engine/Filter.h View File

@@ -1,26 +1,26 @@
/*
==============================================================================
This file is part of Obxd synthesizer.
==============================================================================
This file is part of Obxd synthesizer.

Copyright © 2013-2014 Filatov Vadim
Copyright © 2013-2014 Filatov Vadim
Contact author via email :
justdat_@_e1.ru
This file may be licensed under the terms of of the
GNU General Public License Version 2 (the ``GPL'').
Software distributed under the License is distributed
on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either
express or implied. See the GPL for the specific language
governing rights and limitations.
You should have received a copy of the GPL along with this
program. If not, go to http://www.gnu.org/licenses/gpl.html
or write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
==============================================================================
*/
Contact author via email :
justdat_@_e1.ru
This file may be licensed under the terms of of the
GNU General Public License Version 2 (the ``GPL'').
Software distributed under the License is distributed
on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either
express or implied. See the GPL for the specific language
governing rights and limitations.
You should have received a copy of the GPL along with this
program. If not, go to http://www.gnu.org/licenses/gpl.html
or write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
==============================================================================
*/
#pragma once
#include "ObxdVoice.h"
#include <math.h>
@@ -32,6 +32,7 @@ private:
float R24;
float rcor,rcorInv;
float rcor24,rcor24Inv;

//24 db multimode
float mmt;
int mmch;
@@ -40,14 +41,16 @@ public:
float sampleRateInv;
bool bandPassSw;
float mm;
bool selfOscPush;
Filter()
{
selfOscPush = false;
bandPassSw = false;
mm=0;
s1=s2=s3=s4=0;
SampleRate = 44000;
sampleRateInv = 1 / SampleRate;
rcor =560.0 / 44000;
rcor =500.0 / 44000;
rcorInv = 1 / rcor;
rcor24 = 970.0 / 44000;
rcor24Inv = 1 / rcor24;
@@ -65,7 +68,7 @@ public:
SampleRate = sr;
sampleRateInv = 1/SampleRate;
float rcrate =sqrt((44000/SampleRate));
rcor = (480.0 / 44000)*rcrate;
rcor = (500.0 / 44000)*rcrate;
rcor24 = (970.0 / 44000)*rcrate;
rcorInv = 1 / rcor;
rcor24Inv = 1 / rcor24;
@@ -75,23 +78,74 @@ public:
R = 1-res;
R24 =( 3.5 * res);
}
inline float diodePairResistanceApprox(float x)
{
return (((((0.0103592f)*x + 0.00920833f)*x + 0.185f)*x + 0.05f )*x + 1.0f);
//Taylor approx of slightly mismatched diode pair
}
//resolve 0-delay feedback
inline float NR(float sample, float g)
{
float y = ((sample- R * s1*2 - g*s1 - s2)/(1+ g*(2*R + g))) + dc;
//calculating feedback non-linear transconducance and compensated for R (-1)
//Boosting non-linearity
float tCfb;
if(!selfOscPush)
tCfb = diodePairResistanceApprox(s1*0.0876f) - 1.0f;
else
tCfb = diodePairResistanceApprox(s1*0.0876f) - 1.035f;
//float tCfb = 0;
//disable non-linearity == digital filter

//resolve linear feedback
float y = ((sample - 2*(s1*(R+tCfb)) - g*s1 - s2)/(1+ g*(2*(R+tCfb)+ g)));

//float y = ((sample - 2*(s1*(R+tCfb)) - g2*s1 - s2)/(1+ g1*(2*(R+tCfb)+ g2)));

return y;
}
inline float Apply(float sample,float g)
{
float gpw = tanf(g *sampleRateInv * juce::float_Pi);
g = gpw;
//float v = ((sample- R * s1*2 - g2*s1 - s2)/(1+ R*g1*2 + g1*g2));
float v = NR(sample,g);

float y1 = v*g + s1;
s1 = v*g + y1;

float y2 = y1*g + s2;
s2 = y1*g + y2;

float mc;
if(!bandPassSw)
mc = (1-mm)*y2 + (mm)*v;
else
{

mc =2 * ( mm < 0.5 ?
((0.5 - mm) * y2 + (mm) * y1):
((1-mm) * y1 + (mm-0.5) * v)
);
}

return mc;
}
inline float NR24(float sample,float g,float lpc)
{
float ml = 1 / (1+g);
float S = (lpc*(lpc*(lpc*s1 + s2) + s3) +s4)*ml;
float G = lpc*lpc*lpc*lpc;
float y = (sample - R24 * S) / (1 + R24*G);
return y + 1e-8;
return y;
}
inline float Apply4Pole(float sample,float g)
{
float g1 = (float)tan(g *sampleRateInv * juce::float_Pi);
g = g1;


float lpc = g / (1 + g);
float y0 = NR24(sample,g,lpc);
@@ -106,7 +160,7 @@ public:
float y2 = tptpc(s2,y1,g);
float y3 = tptpc(s3,y2,g);
float y4 = tptpc(s4,y3,g);
float mc = 0.0f;
float mc;
switch(mmch)
{
case 0:
@@ -121,35 +175,11 @@ public:
case 3:
mc = y1;
break;
default:
mc=0;
break;
}
//half volume comp
return mc * (1 + R24 * 0.45);
}
inline float Apply(float sample,float g)
{
float g1 = (float)tan(g *sampleRateInv * juce::float_Pi);
g = g1;
//float v = ((sample- R * s1*2 - g2*s1 - s2)/(1+ R*g1*2 + g1*g2));
float v = NR(sample,g);
float y1 = v*g + s1;
s1 = v*g+y1;
//damping
s1 = atan(s1 * rcor) * rcorInv;

float y2 = y1*g + s2;
s2 = y2 + y1*g;
double mc;
if(!bandPassSw)
mc = (1-mm)*y2 + (mm)*v;
else
{

mc =2 * ( mm < 0.5 ?
((0.5 - mm) * y2 + (mm) * y1):
((1-mm) * y1 + (mm-0.5) * v)
);
}

return mc;
}
};
};

+ 88
- 3
ports/obxd/source/Engine/Lfo.h View File

@@ -32,17 +32,48 @@ private:
Random rg;
float SampleRate;
float SampleRateInv;

float syncRate;
bool synced;

public:
float Frequency;
float phaseInc;
float frUnsc;//frequency value without sync
float rawParam;
int waveForm;
Lfo()
{
phaseInc = 0;
frUnsc=0;
syncRate = 1;
rawParam=0;
synced = false;
s1=0;
Frequency=1;
phase=0;
s=sq=sh=0;
rg=Random();
}
void setSynced()
{
synced = true;
recalcRate(rawParam);
}
void setUnsynced()
{
synced = false;
phaseInc = frUnsc;
}
void hostSyncRetrigger(float bpm,float quaters)
{
if(synced)
{
phaseInc = (bpm/60.0)*syncRate;
phase = phaseInc*quaters;
phase = (fmod(phase,1)*float_Pi*2-float_Pi);
}
}
inline float getVal()
{
float Res = 0;
@@ -52,7 +83,7 @@ public:
Res+=sq;
if((waveForm&4)!=0)
Res+=sh;
return tptlpupw(s1, Res,700,SampleRateInv);
return tptlpupw(s1, Res,3000,SampleRateInv);
}
void setSamlpeRate(float sr)
{
@@ -61,7 +92,7 @@ public:
}
inline void update()
{
phase+=((Frequency * SampleRateInv * float_Pi*2));
phase+=((phaseInc * float_Pi*2 * SampleRateInv));
sq = (phase>0?1:-1);
s = sin(phase);
if(phase > float_Pi)
@@ -71,4 +102,58 @@ public:
}

}
};
void setFrequency(float val)
{
frUnsc = val;
if(!synced)
phaseInc = val;
}
void setRawParam(float param)//used for synced rate changes
{
rawParam = param;
if(synced)
{
recalcRate(param);
}
}
void recalcRate(float param)
{
const int ratesCount = 9;
int parval = (int)(param*(ratesCount-1));
float rt = 1;
switch(parval)
{
case 0:
rt = 1.0 / 8;
break;
case 1:
rt = 1.0 / 4;
break;
case 2:
rt = 1.0 / 3;
break;
case 3:
rt = 1.0 / 2;
break;
case 4:
rt = 1.0;
break;
case 5:
rt = 3.0 / 2;
break;
case 6:
rt = 2;
break;
case 7:
rt = 3;
break;
case 8:
rt = 4;
break;
default:
rt = 1;
break;
}
syncRate = rt;
}
};

+ 97
- 68
ports/obxd/source/Engine/Motherboard.h View File

@@ -1,33 +1,32 @@
/*
==============================================================================
This file is part of Obxd synthesizer.
==============================================================================
This file is part of Obxd synthesizer.

Copyright © 2013-2014 Filatov Vadim
Copyright � 2013-2014 Filatov Vadim
Contact author via email :
justdat_@_e1.ru
Contact author via email :
justdat_@_e1.ru

This file may be licensed under the terms of of the
GNU General Public License Version 2 (the ``GPL'').
This file may be licensed under the terms of of the
GNU General Public License Version 2 (the ``GPL'').

Software distributed under the License is distributed
on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either
express or implied. See the GPL for the specific language
governing rights and limitations.
Software distributed under the License is distributed
on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either
express or implied. See the GPL for the specific language
governing rights and limitations.

You should have received a copy of the GPL along with this
program. If not, go to http://www.gnu.org/licenses/gpl.html
or write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
==============================================================================
*/
You should have received a copy of the GPL along with this
program. If not, go to http://www.gnu.org/licenses/gpl.html
or write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
==============================================================================
*/
#pragma once
#include <climits>
#include "VoiceQueue.h"
#include "SynthEngine.h"
#include "Lfo.h"

#include <climits>

class Motherboard
{
private:
@@ -37,11 +36,11 @@ private:
bool awaitingkeys[129];
int priorities[129];

Decimator9 left,right;
Decimator17 left,right;
int asPlayedCounter;
float lkl,lkr;
float sampleRate,sampleRateInv;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Motherboard)
//JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Motherboard)
public:
bool asPlayedMode;
Lfo mlfo,vibratoLfo;
@@ -49,13 +48,16 @@ public:
bool vibratoEnabled;

float Volume;
float* pannings;
ObxdVoice** voices;
const static int MAX_VOICES=8;
float pannings[MAX_VOICES];
ObxdVoice voices[MAX_VOICES];
bool uni;
bool Oversample;

bool economyMode;
Motherboard(): left(),right()
{
economyMode = true;
lkl=lkr=0;
vibratoEnabled = true;
asPlayedMode = false;
@@ -73,33 +75,32 @@ public:
uni = false;
wasUni = false;
Volume=0;
voices = new ObxdVoice* [MAX_VOICES];
pannings = new float[MAX_VOICES];
// voices = new ObxdVoice* [MAX_VOICES];
// pannings = new float[MAX_VOICES];
totalvc = MAX_VOICES;
vq = VoiceQueue(MAX_VOICES,voices);
for(int i = 0 ; i < MAX_VOICES;++i)
{
pannings[i]= 0.5;
voices[i]=new ObxdVoice();
}
}
~Motherboard()
{
delete pannings;
for(int i = 0 ; i < MAX_VOICES;++i)
{
delete voices[i];
}
delete voices;
//delete pannings;
//for(int i = 0 ; i < MAX_VOICES;++i)
//{
// delete voices[i];
//}
//delete voices;
}
void setVoiceCount(int count)
{
for(int i = count ; i < MAX_VOICES;i++)
{
voices[i]->NoteOff();
voices[i]->ResetEnvelope();
voices[i].NoteOff();
voices[i].ResetEnvelope();
}
vq.ReInit(count);
vq.reInit(count);
totalvc = count;
}
void unisonOn()
@@ -115,14 +116,15 @@ public:
vibratoLfo.setSamlpeRate(sr);
for(int i = 0 ; i < MAX_VOICES;++i)
{
voices[i]->setSampleRate(sr);
voices[i].setSampleRate(sr);
}
SetOversample(Oversample);
}
void sustainOn()
{
for(int i = 0 ; i < MAX_VOICES;i++)
{
ObxdVoice* p = vq.GetNext();
ObxdVoice* p = vq.getNext();
p->sustOn();
}
}
@@ -130,7 +132,7 @@ public:
{
for(int i = 0 ; i < MAX_VOICES;i++)
{
ObxdVoice* p = vq.GetNext();
ObxdVoice* p = vq.getNext();
p->sustOff();
}
}
@@ -148,7 +150,7 @@ public:
int minmidi = 129;
for(int i = 0 ; i < totalvc; i++)
{
ObxdVoice* p = vq.GetNext();
ObxdVoice* p = vq.getNext();
if(p->midiIndx < minmidi && p->Active)
{
minmidi = p->midiIndx;
@@ -162,7 +164,7 @@ public:
{
for(int i = 0 ; i < totalvc;i++)
{
ObxdVoice* p = vq.GetNext();
ObxdVoice* p = vq.getNext();
if(p->midiIndx > noteNo && p->Active)
{
awaitingkeys[p->midiIndx] = true;
@@ -180,7 +182,7 @@ public:
{
for(int i = 0 ; i < totalvc; i++)
{
ObxdVoice* p = vq.GetNext();
ObxdVoice* p = vq.getNext();
if(p->Active)
{
awaitingkeys[p->midiIndx] = true;
@@ -198,7 +200,7 @@ public:
{
for (int i = 0; i < totalvc && !processed; i++)
{
ObxdVoice* p = vq.GetNext();
ObxdVoice* p = vq.getNext();
if (!p->Active)
{
p->NoteOn(noteNo,velocity);
@@ -216,7 +218,7 @@ public:
ObxdVoice* highestVoiceAvalible = NULL;
for(int i = 0 ; i < totalvc; i++)
{
ObxdVoice* p = vq.GetNext();
ObxdVoice* p = vq.getNext();
if(p->midiIndx > maxmidi)
{
maxmidi = p->midiIndx;
@@ -239,7 +241,7 @@ public:
ObxdVoice* minPriorityVoice = NULL;
for(int i = 0 ; i < totalvc; i++)
{
ObxdVoice* p = vq.GetNext();
ObxdVoice* p = vq.getNext();
if(priorities[p->midiIndx] <minPriority)
{
minPriority = priorities[p->midiIndx];
@@ -282,7 +284,7 @@ public:
{
for(int i = 0 ; i < totalvc; i++)
{
ObxdVoice* p = vq.GetNext();
ObxdVoice* p = vq.getNext();
if((p->midiIndx == noteNo) && (p->Active))
{
p->NoteOn(reallocKey,-0.5);
@@ -296,7 +298,7 @@ public:
{
for (int i = 0; i < totalvc; i++)
{
ObxdVoice* n = vq.GetNext();
ObxdVoice* n = vq.getNext();
if (n->midiIndx==noteNo && n->Active)
{
n->NoteOff();
@@ -306,15 +308,38 @@ public:
}
void SetOversample(bool over)
{
if(over!=Oversample)
if(over==true)
{
for(int i = 0 ; i < MAX_VOICES;i++)
{
voices[i]->ToogleOversample();
}
mlfo.setSamlpeRate(sampleRate*2);
vibratoLfo.setSamlpeRate(sampleRate*2);
}
else
{
mlfo.setSamlpeRate(sampleRate);
vibratoLfo.setSamlpeRate(sampleRate);
}
for(int i = 0 ; i < MAX_VOICES;i++)
{
voices[i].setHQ(over);
if(over)
voices[i].setSampleRate(sampleRate*2);
else
voices[i].setSampleRate(sampleRate);
}
Oversample = over;
}
inline float processSynthVoice(ObxdVoice& b,float lfoIn,float vibIn )
{
if(economyMode)
b.checkAdsrState();
if(b.shouldProcessed||(!economyMode))
{
b.lfoIn=lfoIn;
b.lfoVibratoIn=vibIn;
return b.ProcessSample();
}
return 0;
}
void processSample(float* sm1,float* sm2)
{
mlfo.update();
@@ -323,29 +348,33 @@ public:
float vlo = 0 , vro = 0 ;
float lfovalue = mlfo.getVal();
float viblfo = vibratoEnabled?(vibratoLfo.getVal() * vibratoAmount):0;
float lfovalue2=0,viblfo2=0;
if(Oversample)
{
mlfo.update();
vibratoLfo.update();
lfovalue2 = mlfo.getVal();
viblfo2 = vibratoEnabled?(vibratoLfo.getVal() * vibratoAmount):0;
}

for(int i = 0 ; i < totalvc;i++)
{
float mem[2] = {0,0};
voices[i]->lfoIn=lfovalue;
voices[i]->lfoVibratoIn=viblfo;
(voices[i]->ProcessSample(mem));
float x1 = mem[0];
vl+=x1*(1-pannings[i]);
vr+=x1*(pannings[i]);
if(Oversample)
{
float x2 = mem[1];
vlo+=x2*(1-pannings[i]);
vro+=x2*(pannings[i]);
}
float x1 = processSynthVoice(voices[i],lfovalue,viblfo);
if(Oversample)
{
float x2 = processSynthVoice(voices[i],lfovalue2,viblfo2);
vlo+=x2*(1-pannings[i]);
vro+=x2*(pannings[i]);
}
vl+=x1*(1-pannings[i]);
vr+=x1*(pannings[i]);
}
if(Oversample)
{
//Variables are swapped!
vl = left.Calc(vlo,vl);
vr = right.Calc(vro,vr);
vl = left.Calc(vl,vlo);
vr = right.Calc(vr,vro);
}
*sm1 = vl*Volume;
*sm2 = vr*Volume;
}
};
};

+ 0
- 0
ports/obxd/source/Engine/ObxdBank.h View File


+ 60
- 43
ports/obxd/source/Engine/ObxdOscillatorB.h View File

@@ -2,7 +2,7 @@
==============================================================================
This file is part of Obxd synthesizer.

Copyright © 2013-2014 Filatov Vadim
Copyright � 2013-2014 Filatov Vadim
Contact author via email :
justdat_@_e1.ru
@@ -50,13 +50,12 @@ private:
//blep const
const int n;
const int hsam;
const float *Blep;
//delay line implements fixed sample delay
DelayLine *del1,*del2;
DelayLine *xmodd;
DelayLineBoolean *syncd;
DelayLine *syncFracd;
DelayLine *cvd;
DelayLine<Samples> del1,del2;
DelayLine<Samples> xmodd;
DelayLineBoolean<Samples> syncd;
DelayLine<Samples> syncFracd;
DelayLine<Samples> cvd;
Random wn;
SawOsc o1s,o2s;
PulseOsc o1p,o2p;
@@ -66,6 +65,8 @@ public:
float tune;//+-1
int oct;

float dirt;

float notePlaying;


@@ -95,11 +96,11 @@ public:
ObxdOscillatorB() :
n(Samples*2),
hsam(Samples),
Blep(blep),
o1s(),o2s(),
o1p(),o2p(),
o1t(),o2t()
{
dirt = 0.1;
totalDetune = 0;
wn = Random(Random::getSystemRandom().nextInt64());
osc1Factor = wn.nextFloat()-0.5;
@@ -118,25 +119,42 @@ public:
notePlaying = 30;
pulseWidth = 0;
o1mx=o2mx=0;
Blep = blep;
x1=wn.nextFloat();
x2=wn.nextFloat();

del1 = new DelayLine(hsam);
del2 = new DelayLine(hsam);
xmodd = new DelayLine(hsam);
syncd = new DelayLineBoolean(hsam);
syncFracd = new DelayLine(hsam);
cvd = new DelayLine(hsam);
//del1 = new DelayLine(hsam);
//del2 = new DelayLine(hsam);
//xmodd = new DelayLine(hsam);
//syncd = new DelayLineBoolean(hsam);
//syncFracd = new DelayLine(hsam);
//cvd = new DelayLine(hsam);
}
~ObxdOscillatorB()
{
delete del1;
delete del2;
delete xmodd;
delete cvd;
delete syncd;
delete syncFracd;
//delete del1;
//delete del2;
//delete xmodd;
//delete cvd;
//delete syncd;
//delete syncFracd;
}
void setDecimation()
{
o1p.setDecimation();
o1t.setDecimation();
o1s.setDecimation();
o2p.setDecimation();
o2t.setDecimation();
o2s.setDecimation();
}
void removeDecimation()
{
o1p.removeDecimation();
o1t.removeDecimation();
o1s.removeDecimation();
o2p.removeDecimation();
o2t.removeDecimation();
o2s.removeDecimation();
}
void setSampleRate(float sr)
{
@@ -145,35 +163,38 @@ public:
}
inline float ProcessSample()
{
pitch1 = getPitch(notePlaying + (quantizeCw?((int)(osc1p)):osc1p)+ pto1 + tune + oct+totalDetune*osc1Factor);
if(pitch1 > 21000)
pitch1 = 21000;
float noiseGen = wn.nextFloat()-0.5;
pitch1 = getPitch(dirt * noiseGen + notePlaying + (quantizeCw?((int)(osc1p)):osc1p)+ pto1 + tune + oct+totalDetune*osc1Factor);
bool hsr = false;
float hsfrac=0;
float fs = pitch1*(sampleRateInv);
float fs = jmin(pitch1*(sampleRateInv),0.45f);
x1+=fs;
hsfrac = 0;
float osc1mix=0.0f;
float pwcalc =jlimit<float>(0.1f,1.0f,(pulseWidth + pw1)*0.5f + 0.5f);

if(osc1Pul)
o1p.processMaster(x1,fs,hsr,hsfrac,pwcalc,pw1w);
o1p.processMaster(x1,fs,pwcalc,pw1w);
if(osc1Saw)
o1s.processMaster(x1,fs,hsr,hsfrac);
o1s.processMaster(x1,fs);
else if(!osc1Pul)
o1t.processMaster(x1,fs,hsr,hsfrac);
o1t.processMaster(x1,fs);

if(x1 >= 1.0f)
{
x1-=1.0f;
hsfrac = x1/fs;
hsr = true;
}


pw1w = pwcalc;

hsr &= hardSync;
//Delaying our hard sync gate signal and frac
syncd->feedDelay(hsr);
syncFracd ->feedDelay(hsfrac);
hsr = syncd->getDelayedSample();
hsfrac = syncFracd->getDelayedSample();
hsr = syncd.feedReturn(hsr) != 0.0f;
hsfrac = syncFracd.feedReturn(hsfrac);

if(osc1Pul)
osc1mix += o1p.getValue(x1,pwcalc) + o1p.aliasReduction();
@@ -184,13 +205,10 @@ public:
//Pitch control needs additional delay buffer to compensate
//This will give us less aliasing on xmod
//Hard sync gate signal delayed too
cvd->feedDelay( getPitch(notePlaying + osc2Det + (quantizeCw?((int)(osc2p)):osc2p) + pto2+ osc1mix *xmod + tune + oct +totalDetune*osc2Factor));
pitch2 = cvd->getDelayedSample();

noiseGen = wn.nextFloat()-0.5;
pitch2 = getPitch(cvd.feedReturn(dirt *noiseGen + notePlaying + osc2Det + (quantizeCw?((int)(osc2p)):osc2p) + pto2+ osc1mix *xmod + tune + oct +totalDetune*osc2Factor));

if(pitch2>21000)
pitch2=21000;
fs = pitch2 * (sampleRateInv);
fs = jmin(pitch2 * (sampleRateInv),0.45f);

pwcalc = jlimit<float>(0.1f,1.0f,(pulseWidth + pw2)*0.5f + 0.5f);

@@ -218,9 +236,8 @@ public:
x2 =fracMaster;
}
//Delaying osc1 signal
xmodd ->feedDelay(osc1mix);
//And getting delayed back
osc1mix = xmodd->getDelayedSample();
osc1mix = xmodd.feedReturn(osc1mix);

if(osc2Pul)
osc2mix += o2p.getValue(x2,pwcalc) + o2p.aliasReduction();
@@ -229,8 +246,8 @@ public:
else if(!osc2Pul)
osc2mix = o2t.getValue(x2) + o2t.aliasReduction();

//mixing
float res =o1mx*osc1mix + o2mx *osc2mix + (wn.nextFloat()-0.5)*(nmx*1.3);
//mixing
float res =o1mx*osc1mix + o2mx *osc2mix + (noiseGen)*(nmx*1.3 + 0.0006);
return res*3;
}
};
};

+ 108
- 67
ports/obxd/source/Engine/ObxdVoice.h View File

@@ -2,7 +2,7 @@
==============================================================================
This file is part of Obxd synthesizer.

Copyright © 2013-2014 Filatov Vadim
Copyright � 2013-2014 Filatov Vadim
Contact author via email :
justdat_@_e1.ru
@@ -40,9 +40,13 @@ private:
float d1,d2;
float c1,c2;

JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ObxdVoice)
bool hq;

//JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ObxdVoice)
public:
bool sustainHold;
//bool resetAdsrsOnAttack;

AdsrEnvelope env;
AdsrEnvelope fenv;
ObxdOscillatorB osc;
@@ -64,12 +68,17 @@ public:
float PortaDetune;
float PortaDetuneAmt;

float levelDetune;
float levelDetuneAmt;

float brightCoef;

int midiIndx;

bool Active;
bool fltKF;
bool shouldProcessed;

float fltKF;

float porta;
float prtst;
@@ -88,13 +97,22 @@ public:
bool lfopw1,lfopw2;

bool Oversample;
bool selfOscPush;

float envpitchmod;
float pwenvmod;

float pwOfs;
bool pwEnvBoth;
bool pitchModBoth;

bool invertFenv;


bool fourpole;


DelayLine *lenvd,*fenvd;
DelayLine<Samples*2> lenvd,fenvd,lfod;

ApInterpolator ap;
float oscpsw;
@@ -102,9 +120,17 @@ public:
float briHold;

ObxdVoice()
: ng(), ap()
: ap()
{
hq = false;
selfOscPush = false;
pitchModBoth = false;
pwOfs = 0 ;
invertFenv = false;
pwEnvBoth = false;
ng = Random(Random::getSystemRandom().nextInt64());
sustainHold = false;
shouldProcessed = false;
vamp=vflt=0;
velocityValue=0;
lfoVibratoIn=0;
@@ -112,6 +138,7 @@ public:
legatoMode = 0;
brightCoef =briHold= 1;
envpitchmod = 0;
pwenvmod = 0;
oscpsw = 0;
cutoffwas = envelopewas=0;
Oversample= false;
@@ -120,6 +147,7 @@ public:
lfoIn=0;
PortaDetuneAmt=0;
FltDetAmt=0;
levelDetuneAmt=0;
porta =0;
prtst=0;
fltKF= false;
@@ -127,80 +155,75 @@ public:
fenvamt = 0;
Active = false;
midiIndx = 30;
levelDetune = Random::getSystemRandom().nextFloat()-0.5;
EnvDetune = Random::getSystemRandom().nextFloat()-0.5;
FenvDetune = Random::getSystemRandom().nextFloat()-0.5;
FltDetune = Random::getSystemRandom().nextFloat()-0.5;
PortaDetune =Random::getSystemRandom().nextFloat()-0.5;
lenvd=new DelayLine(Samples*2);
fenvd=new DelayLine(Samples*2);
// lenvd=new DelayLine(Samples*2);
// fenvd=new DelayLine(Samples*2);
}
~ObxdVoice()
{
delete lenvd;
delete fenvd;
// delete lenvd;
// delete fenvd;
}
inline void ProcessSample(float* ptr)
inline float ProcessSample()
{
//portamento on osc input voltage
//implements rc circuit
float ptNote =tptlpupw(prtst, midiIndx-81, porta * (1+PortaDetune*PortaDetuneAmt),sampleRateInv);
osc.notePlaying = ptNote;
//both envelopes needs a delay equal to osc internal delay
//both envelopes and filter cv need a delay equal to osc internal delay
float lfoDelayed = lfod.feedReturn(lfoIn);
//filter envelope undelayed
float envm = fenv.processSample() * (1 - (1-velocityValue)*vflt);
fenvd->feedDelay(envm);
float cutoffcalc = jmin(getPitch((lfof?lfoIn*lfoa1:0)+cutoff+FltDetune*FltDetAmt+ fenvamt*fenvd->getDelayedSample() -45 + (fltKF ?ptNote+40:0)), (flt.SampleRate*0.5f-120.0f));
lenvd->feedDelay(env.processSample() * (1 - (1-velocityValue)*vamp));

osc.pw1 = lfopw1?lfoIn*lfoa2:0;
osc.pw2 = lfopw2?lfoIn*lfoa2:0;
osc.pto1 = (!pitchWheelOsc2Only? (pitchWheel*pitchWheelAmt):0 ) + ( lfoo1?lfoIn*lfoa1:0) + lfoVibratoIn;
if(invertFenv)
envm = -envm;
//filter exp cutoff calculation
float cutoffcalc = jmin(
getPitch(
(lfof?lfoDelayed*lfoa1:0)+
cutoff+
FltDetune*FltDetAmt+
fenvamt*fenvd.feedReturn(envm)+
-45 + (fltKF*(ptNote+40))
)
//noisy filter cutoff
+(ng.nextFloat()-0.5f)*3.5f
, (flt.SampleRate*0.5f-120.0f));//for numerical stability purposes

//limit our max cutoff on self osc to prevent alising
if(selfOscPush)
cutoffcalc = jmin(cutoffcalc,19000.0f);


//PW modulation
osc.pw1 = (lfopw1?(lfoIn * lfoa2):0) + (pwEnvBoth?(pwenvmod * envm) : 0);
osc.pw2 = (lfopw2?(lfoIn * lfoa2):0) + pwenvmod * envm + pwOfs;

//Pitch modulation
osc.pto1 = (!pitchWheelOsc2Only? (pitchWheel*pitchWheelAmt):0 ) + ( lfoo1?(lfoIn * lfoa1):0) + (pitchModBoth?(envpitchmod * envm):0) + lfoVibratoIn;
osc.pto2 = (pitchWheel *pitchWheelAmt) + (lfoo2?lfoIn*lfoa1:0) + (envpitchmod * envm) + lfoVibratoIn;



//variable sort magic
float env = lenvd->getDelayedSample();
//variable sort magic - upsample trick
float envVal = lenvd.feedReturn(env.processSample() * (1 - (1-velocityValue)*vamp));

float x2 = 0;
float oscps = osc.ProcessSample();
oscps = oscps - 0.45*tptlpupw(c1,oscps,15,sampleRateInv);
if(Oversample)
{
x2= oscpsw;
x2 = tptpc(d2,x2,brightCoef);
if(fourpole)
x2 = flt.Apply4Pole(x2,(cutoffcalc+cutoffwas)*0.5);
else
x2 = flt.Apply(x2,(cutoffcalc+cutoffwas)*0.5);
x2 *= (env+envelopewas)*0.5;
*(ptr+1) = x2;
}
float x1;
if(!Oversample)
{
x1 = oscps;
x1 = tptpc(d2,x1,brightCoef);
if(fourpole)
x1 = flt.Apply4Pole(x1,(cutoffcalc));
else
x1 = flt.Apply(x1,(cutoffcalc));
float oscps = osc.ProcessSample() * (1 - levelDetuneAmt*levelDetune);

}
else
{
x1 = ap.getInterp(oscps);
x1 = tptpc(d2,x1,brightCoef);
if(fourpole)
x1 = flt.Apply4Pole(x1,(cutoffcalc));
else
x1 = flt.Apply(x1,(cutoffcalc));
}
x1 *= (env);
*(ptr)=x1;

oscpsw = oscps;
cutoffwas = cutoffcalc;
envelopewas = env;
oscps = oscps - tptlpupw(c1,oscps,12,sampleRateInv);

float x1 = oscps;
x1 = tptpc(d2,x1,brightCoef);
if(fourpole)
x1 = flt.Apply4Pole(x1,(cutoffcalc));
else
x1 = flt.Apply(x1,(cutoffcalc));
x1 *= (envVal);
return x1;
}
void setBrightness(float val)
{
@@ -213,9 +236,20 @@ public:
env.setUniqueDeriviance(1 + EnvDetune*d);
fenv.setUniqueDeriviance(1 + FenvDetune*d);
}
void setHQ(bool hq)
{
if(hq)
{
osc.setDecimation();
}
else
{
osc.removeDecimation();
}
}
void setSampleRate(float sr)
{
flt.setSampleRate((Oversample)?2*sr:sr);
flt.setSampleRate(sr);
osc.setSampleRate(sr);
env.setSampleRate(sr);
fenv.setSampleRate(sr);
@@ -223,21 +257,28 @@ public:
sampleRateInv = 1 / sr;
brightCoef = tan(jmin(briHold,flt.SampleRate*0.5f-10)* (juce::float_Pi) * flt.sampleRateInv);
}
void checkAdsrState()
{
shouldProcessed = env.isActive();
}
void ResetEnvelope()
{
env.ResetEnvelopeState();
fenv.ResetEnvelopeState();
}
void ToogleOversample()
{
flt.setSampleRate((Oversample)?SampleRate:2*SampleRate);
Oversample = !Oversample;
brightCoef = tan(jmin(briHold,flt.SampleRate*0.5f-10)* (juce::float_Pi)* flt.sampleRateInv);
}
void NoteOn(int mididx,float velocity)
{
if(!shouldProcessed)
{
//When your processing is paused we need to clear delay lines and envelopes
//Not doing this will cause clicks or glitches
lenvd.fillZeroes();
fenvd.fillZeroes();
ResetEnvelope();
}
shouldProcessed = true;
if(velocity!=-0.5)
velocityValue = velocity;
velocityValue = velocity;
midiIndx = mididx;
if((!Active)||(legatoMode&1))
env.triggerAttack();
@@ -268,4 +309,4 @@ public:
}

}
};
};

+ 2
- 2
ports/obxd/source/Engine/ParamSmoother.h View File

@@ -24,7 +24,7 @@
#pragma once
#include "SynthEngine.h"

const float PSSC = 0.0120;
const float PSSC = 0.0030;
class ParamSmoother
{
private:
@@ -51,4 +51,4 @@ class ParamSmoother
srCor = sr / 44000;
}

};
};

+ 13
- 7
ports/obxd/source/Engine/Params.h View File

@@ -2,7 +2,7 @@
==============================================================================
This file is part of Obxd synthesizer.

Copyright © 2013-2014 Filatov Vadim
Copyright � 2013-2014 Filatov Vadim
Contact author via email :
justdat_@_e1.ru
@@ -27,12 +27,12 @@
class ObxdParams
{
public:
float* values;
float values[PARAM_COUNT];
String name;
ObxdParams()
{
name = "Default";
values = new float[PARAM_COUNT];
//values = new float[PARAM_COUNT];
setDefaultValues();
}
void setDefaultValues()
@@ -47,7 +47,7 @@ public:
values[TUNE] = 0.5f;
values[OSC2_DET]=0.4;
values[LSUS]=1.0f;
values[CUTOFF]=0.5f;
values[CUTOFF]=1.0f;
values[VOLUME]=0.5f;
values[OSC1MIX]=1;
values[OSC2MIX]=1;
@@ -64,10 +64,16 @@ public:
values[PAN6]=0.5;
values[PAN7]=0.5;
values[PAN8]=0.5;
values[ECONOMY_MODE] = 1;
values[ENVDER] = 0.3;
values[FILTERDER]=0.3;
values[LEVEL_DIF]=0.3;
values[PORTADER]=0.3;
values[UDET]=0.2;
}
~ObxdParams()
{
delete values;
//delete values;
}
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(ObxdParams)
};
//JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(ObxdParams)
};

+ 12
- 3
ports/obxd/source/Engine/ParamsEnum.h View File

@@ -26,7 +26,7 @@
enum ObxdParameters
{
UNDEFINED,
UNDEFINED2,
UNUSED_1,
VOLUME,
VOICE_COUNT,
TUNE,
@@ -80,6 +80,15 @@ enum ObxdParameters
FREL,
ENVDER,FILTERDER,PORTADER,
PAN1,PAN2,PAN3,PAN4,PAN5,PAN6,PAN7,PAN8,
UNDEFINED3,
UNUSED_2,
ECONOMY_MODE,
LFO_SYNC,
PW_ENV,
PW_ENV_BOTH,
ENV_PITCH_BOTH,
FENV_INVERT,
PW_OSC2_OFS,
LEVEL_DIF,
SELF_OSC_PUSH,
PARAM_COUNT,
};
};

+ 30
- 39
ports/obxd/source/Engine/PulseOsc.h View File

@@ -2,7 +2,7 @@
==============================================================================
This file is part of Obxd synthesizer.

Copyright © 2013-2014 Filatov Vadim
Copyright � 2013-2014 Filatov Vadim
Contact author via email :
justdat_@_e1.ru
@@ -26,43 +26,51 @@
#include "BlepData.h"
class PulseOsc
{
DelayLine* del1;
DelayLine<Samples> del1;
bool pw1t;
float *buffer1;
float buffer1[Samples*2];
const int hsam;
const int n;
float const * blepPTR;
int bP1;
public:
PulseOsc() : hsam(Samples)
, n(Samples*2)
{
del1 = new DelayLine(hsam);
// del1 = new DelayLine(hsam);
pw1t = false;
bP1=0;
buffer1= new float[n];
//buffer1= new float[n];
for(int i = 0 ; i < n ; i++)
buffer1[i]=0;
blepPTR = blep;
}
~PulseOsc()
{
delete buffer1;
delete del1;
// delete buffer1;
// delete del1;
}
inline void setDecimation()
{
blepPTR = blepd2;
}
inline void removeDecimation()
{
blepPTR = blep;
}
inline float aliasReduction()
{
return -getNextBlep(buffer1,bP1);
}
inline void processMaster(float x,float delta,bool& hardSyncReset,float& hardSyncFrac,float pulseWidth,float pulseWidthWas)
inline void processMaster(float x,float delta,float pulseWidth,float pulseWidthWas)
{
float summated = delta- (pulseWidth - pulseWidthWas);
if((pw1t) && x >= 1.0f)
{
x -= 1.0f;
hardSyncFrac = x/delta;
if(pw1t)
mixInImpulseCenter(buffer1,bP1,x/delta, 1);
pw1t=false;
hardSyncReset = true;
}
if((!pw1t)&& (x >= pulseWidth)&&(x - summated <=pulseWidth))
{
@@ -73,11 +81,9 @@ public:
if((pw1t) && x >= 1.0f)
{
x-=1.0f;
hardSyncFrac = x/delta;
if(pw1t)
mixInImpulseCenter(buffer1,bP1,x/delta, 1);
pw1t=false;
hardSyncReset = true;
}

}
@@ -88,8 +94,7 @@ public:
oscmix = 1 - (0.5-pulseWidth) - 0.5;
else
oscmix = -(0.5-pulseWidth) - 0.5;
del1->feedDelay(oscmix);
return del1->getDelayedSample();
return del1.feedReturn(oscmix);
}
inline float getValueFast(float x,float pulseWidth)
{
@@ -163,30 +168,19 @@ public:
{
int lpIn =(int)(B_OVERSAMPLING*(offset));
float frac = offset * B_OVERSAMPLING - lpIn;
for(int i = 0 ; i <n;i++)
float f1 = 1.0f-frac;
for(int i = 0 ; i < Samples;i++)
{
float mixvalue = 0;
mixvalue = (blep[lpIn]*(1-frac)+blep[lpIn+1]*(frac));
if(i>=Samples)
mixvalue-=1;
float mixvalue = (blepPTR[lpIn]*f1+blepPTR[lpIn+1]*(frac));
buf[(bpos+i)&(n-1)] += mixvalue*scale;
lpIn += B_OVERSAMPLING;
}
}
inline float getDelayedSample(float* buf,int& dpos)
{
int idx;
idx = dpos-(hsam);
if(idx <0)
idx+=hsam;
return buf[idx];
}
inline void feedDelay(float* buf,int& dpos,float sm)
{
buf[dpos] = sm;
dpos++;
if(dpos >= (hsam))
dpos-=(hsam);
for(int i = Samples ; i <n;i++)
{
float mixvalue = (blepPTR[lpIn]*f1+blepPTR[lpIn+1]*(frac));
buf[(bpos+i)&(n-1)] -= mixvalue*scale;
lpIn += B_OVERSAMPLING;
}
}
inline float getNextBlep(float* buf,int& bpos)
{
@@ -194,10 +188,7 @@ public:
bpos++;

// Wrap pos
if (bpos>=n)
{
bpos -= n;
}
bpos&=(n-1);
return buf[bpos];
}
};
};

+ 29
- 36
ports/obxd/source/Engine/SawOsc.h View File

@@ -26,44 +26,51 @@
#include "BlepData.h"
class SawOsc
{
DelayLine* del1;
float *buffer1;
DelayLine<Samples> del1;
float buffer1[Samples*2];
const int hsam;
const int n;
float const * blepPTR;
int bP1;
public:
SawOsc() : hsam(Samples)
, n(Samples*2)
{
bP1=0;
del1 = new DelayLine(hsam);
buffer1= new float[n];
//del1 = new DelayLine(hsam);
//buffer1= new float[n];
for(int i = 0 ; i < n ; i++)
buffer1[i]=0;
blepPTR = blep;
}
~SawOsc()
{
delete del1;
delete buffer1;
//delete del1;
//delete buffer1;
}
inline void setDecimation()
{
blepPTR = blepd2;
}
inline void removeDecimation()
{
blepPTR = blep;
}
inline float aliasReduction()
{
return -getNextBlep(buffer1,bP1);
}
inline void processMaster(float x,float delta,bool& hardSyncReset,float& hardSyncFrac)
inline void processMaster(float x,float delta)
{
if(x >= 1.0f)
{
x-=1.0f;
hardSyncFrac = x/delta;
mixInImpulseCenter(buffer1,bP1,x/delta, 1);
hardSyncReset = true;
}
}
inline float getValue(float x)
{
del1->feedDelay(x - 0.5);
return del1->getDelayedSample();
return del1.feedReturn(x-0.5);
}
inline float getValueFast(float x)
{
@@ -95,30 +102,19 @@ public:
{
int lpIn =(int)(B_OVERSAMPLING*(offset));
float frac = offset * B_OVERSAMPLING - lpIn;
for(int i = 0 ; i <n;i++)
float f1 = 1.0f-frac;
for(int i = 0 ; i < Samples;i++)
{
float mixvalue = 0;
mixvalue = (blep[lpIn]*(1-frac)+blep[lpIn+1]*(frac));
if(i>=Samples)
mixvalue-=1;
float mixvalue = (blepPTR[lpIn]*f1+blepPTR[lpIn+1]*frac);
buf[(bpos+i)&(n-1)] += mixvalue*scale;
lpIn += B_OVERSAMPLING;
}
}
inline float getDelayedSample(float* buf,int& dpos)
{
int idx;
idx = dpos-(hsam);
if(idx <0)
idx+=hsam;
return buf[idx];
}
inline void feedDelay(float* buf,int& dpos,float sm)
{
buf[dpos] = sm;
dpos++;
if(dpos >= (hsam))
dpos-=(hsam);
for(int i = Samples ; i <n;i++)
{
float mixvalue = (blepPTR[lpIn]*f1+blepPTR[lpIn+1]*frac);
buf[(bpos+i)&(n-1)] -= mixvalue*scale;
lpIn += B_OVERSAMPLING;
}
}
inline float getNextBlep(float* buf,int& bpos)
{
@@ -126,10 +122,7 @@ public:
bpos++;

// Wrap pos
if (bpos>=n)
{
bpos -= n;
}
bpos&=(n-1);
return buf[bpos];
}
};
};

+ 186
- 136
ports/obxd/source/Engine/SynthEngine.h View File

@@ -2,7 +2,7 @@
==============================================================================
This file is part of Obxd synthesizer.

Copyright © 2013-2014 Filatov Vadim
Copyright ) 2013-2014 Filatov Vadim
Contact author via email :
justdat_@_e1.ru
@@ -32,29 +32,35 @@
class SynthEngine
{
private:
Motherboard * synth;
Motherboard synth;
ParamSmoother cutoffSmoother;
ParamSmoother pitchWheelSmoother;
ParamSmoother modWheelSmoother;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SynthEngine)
float sampleRate;
//JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SynthEngine)
public:
SynthEngine():
cutoffSmoother(),
//synth = new Motherboard();
pitchWheelSmoother(),
modWheelSmoother()
{
synth = new Motherboard();
}
~SynthEngine()
{
delete synth;
//delete synth;
}
void setPlayHead(float bpm,float retrPos)
{
synth.mlfo.hostSyncRetrigger(bpm,retrPos);
}
void setSampleRate(float sr)
{
sampleRate = sr;
cutoffSmoother.setSampleRate(sr);
pitchWheelSmoother.setSampleRate(sr);
modWheelSmoother.setSampleRate(sr);
synth->setSampleRate(sr);
synth.setSampleRate(sr);
}
void processSample(float *left,float *right)
{
@@ -62,7 +68,7 @@ public:
procPitchWheelSmoothed(pitchWheelSmoother.smoothStep());
procModWheelSmoothed(modWheelSmoother.smoothStep());

synth->processSample(left,right);
synth.processSample(left,right);
}
void allNotesOff()
{
@@ -76,41 +82,58 @@ public:
allNotesOff();
for(int i = 0 ; i < Motherboard::MAX_VOICES;i++)
{
synth->voices[i]->ResetEnvelope();
synth.voices[i].ResetEnvelope();
}
}
void sustainOn()
{
synth->sustainOn();
synth.sustainOn();
}
void sustainOff()
{
synth->sustainOff();
synth.sustainOff();
}
void procLfoSync(float val)
{
if(val > 0.5)
synth.mlfo.setSynced();
else
synth.mlfo.setUnsynced();
}
void procAsPlayedAlloc(float val)
{
synth->asPlayedMode = val > 0.5;
synth.asPlayedMode = val > 0.5;
}
void procNoteOn(int noteNo,float velocity)
{
synth->setNoteOn(noteNo,velocity);
synth.setNoteOn(noteNo,velocity);
}
void procNoteOff(int noteNo)
{
synth->setNoteOff(noteNo);
synth.setNoteOff(noteNo);
}
void procEconomyMode(float val)
{
synth.economyMode = val>0.5;
}
#define ForEachVoice(expr) \
for(int i = 0 ; i < synth.MAX_VOICES;i++) \
{\
synth.voices[i].expr;\
}\

void procAmpVelocityAmount(float val)
{
for(int i = 0 ; i < synth->MAX_VOICES;i++)
for(int i = 0 ; i < synth.MAX_VOICES;i++)
{
synth->voices[i]->vamp= val;
synth.voices[i].vamp= val;
}
}
void procFltVelocityAmount(float val)
{
for(int i = 0 ; i < synth->MAX_VOICES;i++)
for(int i = 0 ; i < synth.MAX_VOICES;i++)
{
synth->voices[i]->vflt= val;
synth.voices[i].vflt= val;
}
}
void procModWheel(float val)
@@ -119,12 +142,12 @@ public:
}
void procModWheelSmoothed(float val)
{
synth->vibratoAmount = val;
synth.vibratoAmount = val;
}
void procModWheelFrequency(float val)
{
synth->vibratoLfo.Frequency = logsc(val,3,10);
synth->vibratoEnabled = val>0.05;
synth.vibratoLfo.setFrequency (logsc(val,3,10));
synth.vibratoEnabled = val>0.05;
}
void procPitchWheel(float val)
{
@@ -136,280 +159,306 @@ public:
}
inline void procPitchWheelSmoothed(float val)
{
for(int i = 0 ; i < synth->MAX_VOICES;i++)
for(int i = 0 ; i < synth.MAX_VOICES;i++)
{
synth->voices[i]->pitchWheel = val;
synth.voices[i].pitchWheel = val;
}
}
void setVoiceCount(float param)
{
synth->setVoiceCount(roundToInt((param*7) +1));
synth.setVoiceCount(roundToInt((param*7) +1));
}
void procPitchWheelAmount(float param)
{
for(int i = 0 ; i < synth->MAX_VOICES;i++)
for(int i = 0 ; i < synth.MAX_VOICES;i++)
{
synth->voices[i]->pitchWheelAmt = param>0.5?12:2;
synth.voices[i].pitchWheelAmt = param>0.5?12:2;
}
}
void procPitchWheelOsc2Only(float param)
{
for(int i = 0 ; i < synth->MAX_VOICES;i++)
for(int i = 0 ; i < synth.MAX_VOICES;i++)
{
synth->voices[i]->pitchWheelOsc2Only = param>0.5;
synth.voices[i].pitchWheelOsc2Only = param>0.5;
}
}
void processPan(float param,int idx)
{
synth->pannings[idx-1] = param;
synth.pannings[idx-1] = param;
}
void processTune(float param)
{
for(int i = 0 ; i < synth->MAX_VOICES;i++)
for(int i = 0 ; i < synth.MAX_VOICES;i++)
{
synth->voices[i]->osc.tune = param*2-1;
synth.voices[i].osc.tune = param*2-1;
}
}
void processLegatoMode(float param)
{
for(int i = 0 ; i < synth->MAX_VOICES;i++)
for(int i = 0 ; i < synth.MAX_VOICES;i++)
{
synth->voices[i]->legatoMode = roundToInt(param*3 + 1) -1;
synth.voices[i].legatoMode = roundToInt(param*3 + 1) -1;
}
}
void processOctave(float param)
{
for(int i = 0 ; i < synth->MAX_VOICES;i++)
for(int i = 0 ; i < synth.MAX_VOICES;i++)
{
synth->voices[i]->osc.oct = (roundToInt(param*4) -2)*12;
synth.voices[i].osc.oct = (roundToInt(param*4) -2)*12;
}
}
void processFilterKeyFollow(float param)
{
for(int i = 0 ; i < synth->MAX_VOICES;i++)
for(int i = 0 ; i < synth.MAX_VOICES;i++)
{
synth->voices[i]->fltKF = param>0.5;
synth.voices[i].fltKF = param;
}
}
void processSelfOscPush(float param)
{
ForEachVoice(selfOscPush = param>0.5);
ForEachVoice(flt.selfOscPush = param>0.5);
}
void processUnison(float param)
{
synth->uni = param>0.5f;
synth.uni = param>0.5f;
}
void processPortamento(float param)
{
for(int i = 0 ; i < synth->MAX_VOICES;i++)
for(int i = 0 ; i < synth.MAX_VOICES;i++)
{
synth->voices[i]->porta =logsc(1-param,0.14,250,150);
synth.voices[i].porta =logsc(1-param,0.14,250,150);
}
}
void processVolume(float param)
{
synth->Volume = linsc(param,0,0.30);
synth.Volume = linsc(param,0,0.30);
}
void processLfoFrequency(float param)
{
synth->mlfo.Frequency = logsc(param,0,50,120);
synth.mlfo.setRawParam(param);
synth.mlfo.setFrequency(logsc(param,0,50,120));
}
void processLfoSine(float param)
{
if(param>0.5)
{
synth->mlfo.waveForm |=1;
synth.mlfo.waveForm |=1;
}
else
{
synth->mlfo.waveForm&=~1;
synth.mlfo.waveForm&=~1;
}
}
void processLfoSquare(float param)
{
if(param>0.5)
{
synth->mlfo.waveForm |=2;
synth.mlfo.waveForm |=2;
}
else
{
synth->mlfo.waveForm&=~2;
synth.mlfo.waveForm&=~2;
}
}
void processLfoSH(float param)
{
if(param>0.5)
{
synth->mlfo.waveForm |=4;
synth.mlfo.waveForm |=4;
}
else
{
synth->mlfo.waveForm&=~4;
synth.mlfo.waveForm&=~4;
}
}
void processLfoAmt1(float param)
{
for(int i = 0 ; i < synth->MAX_VOICES;i++)
for(int i = 0 ; i < synth.MAX_VOICES;i++)
{
synth->voices[i]->lfoa1 = logsc(logsc(param,0,1,60),0,60,10);
synth.voices[i].lfoa1 = logsc(logsc(param,0,1,60),0,60,10);
}
}
void processLfoOsc1(float param)
{
for(int i = 0 ; i < synth->MAX_VOICES;i++)
for(int i = 0 ; i < synth.MAX_VOICES;i++)
{
synth->voices[i]->lfoo1 = param>0.5;
synth.voices[i].lfoo1 = param>0.5;
}
}
void processLfoOsc2(float param)
{
for(int i = 0 ; i < synth->MAX_VOICES;i++)
for(int i = 0 ; i < synth.MAX_VOICES;i++)
{
synth->voices[i]->lfoo2 = param>0.5;
synth.voices[i].lfoo2 = param>0.5;
}
}
void processLfoFilter(float param)
{
for(int i = 0 ; i < synth->MAX_VOICES;i++)
for(int i = 0 ; i < synth.MAX_VOICES;i++)
{
synth->voices[i]->lfof = param>0.5;
synth.voices[i].lfof = param>0.5;
}
}
void processLfoPw1(float param)
{
for(int i = 0 ; i < synth->MAX_VOICES;i++)
for(int i = 0 ; i < synth.MAX_VOICES;i++)
{
synth->voices[i]->lfopw1 = param>0.5;
synth.voices[i].lfopw1 = param>0.5;
}
}
void processLfoPw2(float param)
{
for(int i = 0 ; i < synth->MAX_VOICES;i++)
for(int i = 0 ; i < synth.MAX_VOICES;i++)
{
synth->voices[i]->lfopw2 = param>0.5;
synth.voices[i].lfopw2 = param>0.5;
}
}
void processLfoAmt2(float param)
{
for(int i = 0 ; i < synth->MAX_VOICES;i++)
for(int i = 0 ; i < synth.MAX_VOICES;i++)
{
synth->voices[i]->lfoa2 = linsc(param,0,0.7);
synth.voices[i].lfoa2 = linsc(param,0,0.7);
}
}
void processDetune(float param)
{
for(int i = 0 ; i < synth->MAX_VOICES;i++)
for(int i = 0 ; i < synth.MAX_VOICES;i++)
{
synth->voices[i]->osc.totalDetune = logsc(param,0.001,0.90);
synth.voices[i].osc.totalDetune = logsc(param,0.001,0.90);
}
}
void processPulseWidth(float param)
{
for(int i = 0 ; i < synth->MAX_VOICES;i++)
for(int i = 0 ; i < synth.MAX_VOICES;i++)
{
synth->voices[i]->osc.pulseWidth = linsc(param,0.0,0.95);
synth.voices[i].osc.pulseWidth = linsc(param,0.0,0.95);
}
}
void processPwEnv(float param)
{
ForEachVoice (pwenvmod=linsc(param,0,0.85));
}
void processPwOfs(float param)
{
ForEachVoice(pwOfs = linsc(param,0,0.75));
}
void processPwEnvBoth(float param)
{
ForEachVoice(pwEnvBoth = param>0.5);
}
void processInvertFenv(float param)
{
ForEachVoice(invertFenv = param>0.5);
}
void processPitchModBoth(float param)
{
ForEachVoice(pitchModBoth = param>0.5);
}
void processOsc2Xmod(float param)
{
for(int i = 0 ; i < synth->MAX_VOICES;i++)
for(int i = 0 ; i < synth.MAX_VOICES;i++)
{
synth->voices[i]->osc.xmod= param*24;
synth.voices[i].osc.xmod= param*24;
}
}
void processEnvelopeToPitch(float param)
{
for(int i = 0 ; i < synth->MAX_VOICES;i++)
for(int i = 0 ; i < synth.MAX_VOICES;i++)
{
synth->voices[i]->envpitchmod= param*36;
synth.voices[i].envpitchmod= param*36;
}
}
void processOsc2HardSync(float param)
{
for(int i = 0 ; i < synth->MAX_VOICES;i++)
for(int i = 0 ; i < synth.MAX_VOICES;i++)
{
synth->voices[i]->osc.hardSync = param>0.5;
synth.voices[i].osc.hardSync = param>0.5;
}
}
void processOsc1Pitch(float param)
{
for(int i = 0 ; i < synth->MAX_VOICES;i++)
for(int i = 0 ; i < synth.MAX_VOICES;i++)
{
synth->voices[i]->osc.osc1p = (param * 48);
synth.voices[i].osc.osc1p = (param * 48);
}
}
void processOsc2Pitch(float param)
{
for(int i = 0 ; i < synth->MAX_VOICES;i++)
for(int i = 0 ; i < synth.MAX_VOICES;i++)
{
synth->voices[i]->osc.osc2p = (param * 48);
synth.voices[i].osc.osc2p = (param * 48);
}
}
void processPitchQuantization(float param)
{
for(int i = 0 ; i < synth->MAX_VOICES;i++)
for(int i = 0 ; i < synth.MAX_VOICES;i++)
{
synth->voices[i]->osc.quantizeCw = param>0.5;
synth.voices[i].osc.quantizeCw = param>0.5;
}
}
void processOsc1Mix(float param)
{
for(int i = 0 ; i < synth->MAX_VOICES;i++)
for(int i = 0 ; i < synth.MAX_VOICES;i++)
{
synth->voices[i]->osc.o1mx = param;
synth.voices[i].osc.o1mx = param;
}
}
void processOsc2Mix(float param)
{
for(int i = 0 ; i < synth->MAX_VOICES;i++)
for(int i = 0 ; i < synth.MAX_VOICES;i++)
{
synth->voices[i]->osc.o2mx = param;
synth.voices[i].osc.o2mx = param;
}
}
void processNoiseMix(float param)
{
for(int i = 0 ; i < synth->MAX_VOICES;i++)
for(int i = 0 ; i < synth.MAX_VOICES;i++)
{
synth->voices[i]->osc.nmx = logsc(param,0,1,35);
synth.voices[i].osc.nmx = logsc(param,0,1,35);
}
}
void processBrightness(float param)
{
for(int i = 0 ; i < synth->MAX_VOICES;i++)
for(int i = 0 ; i < synth.MAX_VOICES;i++)
{
synth->voices[i]->setBrightness( linsc(param,10000,26000));
synth.voices[i].setBrightness( linsc(param,7000,26000));
}
}
void processOsc2Det(float param)
{
for(int i = 0 ; i < synth->MAX_VOICES;i++)
for(int i = 0 ; i < synth.MAX_VOICES;i++)
{
synth->voices[i]->osc.osc2Det = logsc(param,0.001,0.6);
synth.voices[i].osc.osc2Det = logsc(param,0.001,0.6);
}
}

void processOsc1Saw(float param)
{
for(int i = 0 ; i < synth->MAX_VOICES;i++)
for(int i = 0 ; i < synth.MAX_VOICES;i++)
{
synth->voices[i]->osc.osc1Saw = param>0.5;
synth.voices[i].osc.osc1Saw = param>0.5;
}
}
void processOsc1Pulse(float param)
{
for(int i = 0 ; i < synth->MAX_VOICES;i++)
for(int i = 0 ; i < synth.MAX_VOICES;i++)
{
synth->voices[i]->osc.osc1Pul = param>0.5;
synth.voices[i].osc.osc1Pul = param>0.5;
}
}
void processOsc2Saw(float param)
{
for(int i = 0 ; i < synth->MAX_VOICES;i++)
for(int i = 0 ; i < synth.MAX_VOICES;i++)
{
synth->voices[i]->osc.osc2Saw= param>0.5;
synth.voices[i].osc.osc2Saw= param>0.5;
}
}
void processOsc2Pulse(float param)
{
for(int i = 0 ; i < synth->MAX_VOICES;i++)
for(int i = 0 ; i < synth.MAX_VOICES;i++)
{
synth->voices[i]->osc.osc2Pul= param>0.5;
synth.voices[i].osc.osc2Pul= param>0.5;
}
}

@@ -424,130 +473,131 @@ public:
}
inline void processCutoffSmoothed(float param)
{
for(int i = 0 ; i < synth->MAX_VOICES;i++)
{
synth->voices[i]->cutoff = param;
}
ForEachVoice(cutoff=param);
}
void processBandpassSw(float param)
{
for(int i = 0 ; i < synth->MAX_VOICES;i++)
for(int i = 0 ; i < synth.MAX_VOICES;i++)
{
//synth->voices[i]->cutoff = logsc(param,60,19000,30);
synth->voices[i]->flt.bandPassSw = param>0.5;
//synth.voices[i].cutoff = logsc(param,60,19000,30);
synth.voices[i].flt.bandPassSw = param>0.5;
}
}
void processResonance(float param)
{
for(int i = 0 ; i < synth->MAX_VOICES;i++)
for(int i = 0 ; i < synth.MAX_VOICES;i++)
{
synth->voices[i]->flt.setResonance(0.991-logsc(1-param,0,0.991,40));
synth.voices[i].flt.setResonance(0.991-logsc(1-param,0,0.991,40));
}
}
void processFourPole(float param)
{
for(int i = 0 ; i < synth->MAX_VOICES;i++)
for(int i = 0 ; i < synth.MAX_VOICES;i++)
{
//synth->voices[i]->flt ;
synth->voices[i]->fourpole = param>0.5;
//synth.voices[i].flt ;
synth.voices[i].fourpole = param>0.5;
}
}
void processMultimode(float param)
{
for(int i = 0 ; i < synth->MAX_VOICES;i++)
for(int i = 0 ; i < synth.MAX_VOICES;i++)
{
//synth->voices[i]->flt ;
synth->voices[i]->flt.setMultimode(linsc(param,0,1));
//synth.voices[i].flt ;
synth.voices[i].flt.setMultimode(linsc(param,0,1));
}
}
void processOversampling(float param)
{
synth->SetOversample(param>0.5);
synth.SetOversample(param>0.5);
}
void processFilterEnvelopeAmt(float param)
{
for(int i = 0 ; i < synth->MAX_VOICES;i++)
for(int i = 0 ; i < synth.MAX_VOICES;i++)
{
synth->voices[i]->fenvamt = linsc(param,0,140);
synth.voices[i].fenvamt = linsc(param,0,140);
}
}
void processLoudnessEnvelopeAttack(float param)
{
for(int i = 0 ; i < synth->MAX_VOICES;i++)
for(int i = 0 ; i < synth.MAX_VOICES;i++)
{
synth->voices[i]->env.setAttack(logsc(param,4,60000,900));
synth.voices[i].env.setAttack(logsc(param,4,60000,900));
}
}
void processLoudnessEnvelopeDecay(float param)
{
for(int i = 0 ; i < synth->MAX_VOICES;i++)
for(int i = 0 ; i < synth.MAX_VOICES;i++)
{
synth->voices[i]->env.setDecay(logsc(param,4,60000,900));
synth.voices[i].env.setDecay(logsc(param,4,60000,900));
}
}
void processLoudnessEnvelopeRelease(float param)
{
for(int i = 0 ; i < synth->MAX_VOICES;i++)
for(int i = 0 ; i < synth.MAX_VOICES;i++)
{
synth->voices[i]->env.setRelease(logsc(param,4,60000,900));
synth.voices[i].env.setRelease(logsc(param,8,60000,900));
}
}
void processLoudnessEnvelopeSustain(float param)
{
for(int i = 0 ; i < synth->MAX_VOICES;i++)
for(int i = 0 ; i < synth.MAX_VOICES;i++)
{
synth->voices[i]->env.setSustain(param);
synth.voices[i].env.setSustain(param);
}
}
void processFilterEnvelopeAttack(float param)
{
for(int i = 0 ; i < synth->MAX_VOICES;i++)
for(int i = 0 ; i < synth.MAX_VOICES;i++)
{
synth->voices[i]->fenv.setAttack(logsc(param,1,60000,900));
synth.voices[i].fenv.setAttack(logsc(param,1,60000,900));
}
}
void processFilterEnvelopeDecay(float param)
{
for(int i = 0 ; i < synth->MAX_VOICES;i++)
for(int i = 0 ; i < synth.MAX_VOICES;i++)
{
synth->voices[i]->fenv.setDecay(logsc(param,1,60000,900));
synth.voices[i].fenv.setDecay(logsc(param,1,60000,900));
}
}
void processFilterEnvelopeRelease(float param)
{
for(int i = 0 ; i < synth->MAX_VOICES;i++)
for(int i = 0 ; i < synth.MAX_VOICES;i++)
{
synth->voices[i]->fenv.setRelease(logsc(param,1,60000,900));
synth.voices[i].fenv.setRelease(logsc(param,1,60000,900));
}
}
void processFilterEnvelopeSustain(float param)
{
for(int i = 0 ; i < synth->MAX_VOICES;i++)
for(int i = 0 ; i < synth.MAX_VOICES;i++)
{
synth->voices[i]->fenv.setSustain(param);
synth.voices[i].fenv.setSustain(param);
}
}
void processEnvelopeDetune(float param)
{
for(int i = 0 ; i < synth->MAX_VOICES;i++)
for(int i = 0 ; i < synth.MAX_VOICES;i++)
{
synth->voices[i]->setEnvDer(linsc(param,0.0,1));
synth.voices[i].setEnvDer(linsc(param,0.0,1));
}
}
void processFilterDetune(float param)
{
for(int i = 0 ; i < synth->MAX_VOICES;i++)
for(int i = 0 ; i < synth.MAX_VOICES;i++)
{
synth->voices[i]->FltDetAmt = linsc(param,0.0,18);
synth.voices[i].FltDetAmt = linsc(param,0.0,18);
}
}
void processPortamentoDetune(float param)
{
for(int i = 0 ; i < synth->MAX_VOICES;i++)
for(int i = 0 ; i < synth.MAX_VOICES;i++)
{
synth->voices[i]->PortaDetuneAmt = linsc(param,0.0,0.75);
synth.voices[i].PortaDetuneAmt = linsc(param,0.0,0.75);
}
}
void processLoudnessDetune(float param)
{
ForEachVoice(levelDetuneAmt = linsc(param,0.0,0.67));
}

};
};

+ 38
- 50
ports/obxd/source/Engine/TriangleOsc.h View File

@@ -26,44 +26,52 @@
#include "BlepData.h"
class TriangleOsc
{
DelayLine* del1;
DelayLine<Samples> del1;
bool fall;
float *buffer1,*buffer2;
float buffer1[Samples*2];
const int hsam;
const int n;
float const * blepPTR;
float const * blampPTR;

int bP1,bP2;
public:
TriangleOsc() : hsam(Samples)
, n(Samples*2)
{
del1 =new DelayLine(hsam);
//del1 =new DelayLine(hsam);
fall = false;
bP1=bP2=0;
buffer1= new float[n];
// buffer1= new float[n];
for(int i = 0 ; i < n ; i++)
buffer1[i]=0;
buffer2= new float[n];
for(int i = 0 ; i < n ; i++)
buffer2[i]=0;
blepPTR = blep;
blampPTR = blamp;
}
~TriangleOsc()
{
delete buffer1;
delete buffer2;
delete del1;
//delete buffer1;
//delete del1;
}
inline void setDecimation()
{
blepPTR = blepd2;
blampPTR = blampd2;
}
inline void removeDecimation()
{
blepPTR = blep;
blampPTR = blamp;
}
inline float aliasReduction()
{
return -getNextBlep(buffer1,bP1);
}
inline void processMaster(float x,float delta,bool& hardSyncReset,float& hardSyncFrac)
inline void processMaster(float x,float delta)
{
if(x >= 1.0)
{
x-=1.0;
hardSyncFrac = x/delta;
hardSyncReset = true;
mixInBlampCenter(buffer1,bP1,x/delta,-4*Samples*delta);
}
if(x >= 0.5 && x - delta < 0.5)
@@ -73,16 +81,13 @@ public:
if(x >= 1.0)
{
x-=1.0;
hardSyncFrac = x/delta;
hardSyncReset = true;
mixInBlampCenter(buffer1,bP1,x/delta,-4*Samples*delta);
}
}
inline float getValue(float x)
{
float mix = x < 0.5 ? 2*x-0.5 : 1.5-2*x;
del1->feedDelay(mix);
return del1->getDelayedSample();
return del1.feedReturn(mix);
}
inline float getValueFast(float x)
{
@@ -140,45 +145,31 @@ public:
{
int lpIn =(int)(B_OVERSAMPLING*(offset));
float frac = offset * B_OVERSAMPLING - lpIn;
for(int i = 0 ; i <n;i++)
float f1 = 1.0f-frac;
for(int i = 0 ; i < n;i++)
{
float mixvalue = 0;
mixvalue = (blamp[lpIn]*(1-frac)+blamp[lpIn+1]*(frac));
//Substract trivial ramp
if(i >=Samples)
mixvalue -= ((lpIn + frac) / (B_OVERSAMPLING * Samples)) - 1;
buf[(bpos+i)&(n-1)] +=mixvalue*scale;
float mixvalue = (blampPTR[lpIn]*f1+blampPTR[lpIn+1]*(frac));
buf[(bpos+i)&(n-1)] += mixvalue*scale;
lpIn += B_OVERSAMPLING;
}
}
inline void mixInImpulseCenter(float * buf,int& bpos,float offset, float scale)
inline void mixInImpulseCenter(float * buf,int& bpos,float offset, float scale)
{
int lpIn =(int)(B_OVERSAMPLING*(offset));
float frac = offset * B_OVERSAMPLING - lpIn;
for(int i = 0 ; i <n;i++)
float f1 = 1.0f-frac;
for(int i = 0 ; i < Samples;i++)
{
float mixvalue = 0;
mixvalue = (blep[lpIn]*(1-frac)+blep[lpIn+1]*(frac));
if(i>=Samples)
mixvalue-=1;
float mixvalue = (blepPTR[lpIn]*f1+blepPTR[lpIn+1]*(frac));
buf[(bpos+i)&(n-1)] += mixvalue*scale;
lpIn += B_OVERSAMPLING;
}
}
inline float getDelayedSample(float* buf,int& dpos)
{
int idx;
idx = dpos-(hsam);
if(idx <0)
idx+=hsam;
return buf[idx];
}
inline void feedDelay(float* buf,int& dpos,float sm)
{
buf[dpos] = sm;
dpos++;
if(dpos >= (hsam))
dpos-=(hsam);
for(int i = Samples ; i <n;i++)
{
float mixvalue = (blepPTR[lpIn]*f1+blepPTR[lpIn+1]*(frac));
buf[(bpos+i)&(n-1)] -= mixvalue*scale;
lpIn += B_OVERSAMPLING;
}
}
inline float getNextBlep(float* buf,int& bpos)
{
@@ -186,10 +177,7 @@ public:
bpos++;

// Wrap pos
if (bpos>=n)
{
bpos -= n;
}
bpos&=(n-1);
return buf[bpos];
}
};
};

+ 7
- 8
ports/obxd/source/Engine/VoiceQueue.h View File

@@ -2,7 +2,7 @@
==============================================================================
This file is part of Obxd synthesizer.

Copyright © 2013-2014 Filatov Vadim
Copyright ) 2013-2014 Filatov Vadim
Contact author via email :
justdat_@_e1.ru
@@ -26,8 +26,7 @@
class VoiceQueue
{
private:

ObxdVoice** voices;
ObxdVoice* voices;
int idx,total;
public:
VoiceQueue()
@@ -36,20 +35,20 @@ public:
idx = 0;
total = 0;
}
VoiceQueue(int voiceCount,ObxdVoice** voicesReference)
VoiceQueue(int voiceCount,ObxdVoice* voicesReference)
{
voices = voicesReference;
idx = 0;total = voiceCount;
}
inline ObxdVoice* GetNext()
inline ObxdVoice* getNext()
{
idx = idx + 1;
idx %=total;
return voices[idx];
return &voices[idx];
}
inline void ReInit(int voiceCount)
inline void reInit(int voiceCount)
{
total = voiceCount;
idx = idx%total;
}
};
};

+ 0
- 0
ports/obxd/source/Engine/midiMap.h View File


+ 7884
- 0
ports/obxd/source/Gui/BinaryData.cpp
File diff suppressed because it is too large
View File


+ 41
- 0
ports/obxd/source/Gui/BinaryData.h View File

@@ -0,0 +1,41 @@
/* =========================================================================================

This is an auto-generated file: Any edits you make may be overwritten!

*/

#ifndef BINARYDATA_H_12816941_INCLUDED
#define BINARYDATA_H_12816941_INCLUDED

namespace BinaryData
{
extern const char* knoblsd_png;
const int knoblsd_pngSize = 214673;

extern const char* knobssd_png;
const int knobssd_pngSize = 174727;

extern const char* legato_png;
const int legato_pngSize = 7913;

extern const char* voices_png;
const int voices_pngSize = 3496;

extern const char* button_png;
const int button_pngSize = 1794;

extern const char* main_png;
const int main_pngSize = 147135;

// Points to the start of a list of resource names.
extern const char* namedResourceList[];

// Number of elements in the namedResourceList array.
const int namedResourceListSize = 6;

// 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) throw();
}

#endif

+ 4
- 4
ports/obxd/source/Gui/ButtonList.h View File

@@ -2,7 +2,7 @@
==============================================================================
This file is part of Obxd synthesizer.

Copyright © 2013-2014 Filatov Vadim
Copyright � 2013-2014 Filatov Vadim
Contact author via email :
justdat_@_e1.ru
@@ -45,9 +45,9 @@ public:
{
return ((getSelectedId()-1)/ (float)(count-1));
}
void setValue(float val,NotificationType notification)
void setValue(float val,NotificationType notify)
{
setSelectedId((int)(val*(count -1) + 1),notification);
setSelectedId((int)(val*(count -1) + 1),notify);
}
void paintOverChildren(Graphics& g)
{
@@ -57,4 +57,4 @@ public:
}


};
};

+ 0
- 0
ports/obxd/source/Gui/Knob.h View File


+ 0
- 0
ports/obxd/source/Gui/TooglableButton.h View File


+ 0
- 20771
ports/obxd/source/Gui/res.cpp
File diff suppressed because it is too large
View File


+ 0
- 69
ports/obxd/source/Gui/res.h View File

@@ -1,69 +0,0 @@
/*
==============================================================================
This file is part of Obxd synthesizer.

Copyright © 2013-2014 Filatov Vadim
Contact author via email :
justdat_@_e1.ru

This file may be licensed under the terms of of the
GNU General Public License Version 2 (the ``GPL'').

Software distributed under the License is distributed
on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either
express or implied. See the GPL for the specific language
governing rights and limitations.

You should have received a copy of the GPL along with this
program. If not, go to http://www.gnu.org/licenses/gpl.html
or write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
==============================================================================
*/
/* (Auto-generated binary data file). */

#ifndef BINARY_RES_H
#define BINARY_RES_H

namespace res
{
extern const char* about_bmp;
const int about_bmpSize = 214146;

extern const char* background_png;
const int background_pngSize = 78606;

extern const char* button_png;
const int button_pngSize = 1858;

extern const char* button2_png;
const int button2_pngSize = 3390;

extern const char* knobl_png;
const int knobl_pngSize = 102125;

extern const char* knobl2_png;
const int knobl2_pngSize = 100956;

extern const char* knoblsd_png;
const int knoblsd_pngSize = 102093;

extern const char* knobs_png;
const int knobs_pngSize = 72112;

extern const char* knobs2_png;
const int knobs2_pngSize = 72346;

extern const char* knobssd_png;
const int knobssd_pngSize = 71595;

extern const char* legato_png;
const int legato_pngSize = 7155;

extern const char* voices_png;
const int voices_pngSize = 3129;

}

#endif

BIN
ports/obxd/source/Images/button.png View File

Before After
Width: 20  |  Height: 73  |  Size: 1.8KB

BIN
ports/obxd/source/Images/knoblsd.png View File

Before After
Width: 48  |  Height: 6096  |  Size: 210KB

BIN
ports/obxd/source/Images/knobssd.png View File

Before After
Width: 42  |  Height: 5334  |  Size: 171KB

BIN
ports/obxd/source/Images/legato.png View File

Before After
Width: 65  |  Height: 96  |  Size: 7.7KB

BIN
ports/obxd/source/Images/main.png View File

Before After
Width: 1440  |  Height: 450  |  Size: 146KB

BIN
ports/obxd/source/Images/voices.png View File

Before After
Width: 17  |  Height: 192  |  Size: 3.4KB

+ 1
- 0
ports/obxd/source/JuceHeader.h View File

@@ -14,6 +14,7 @@
#define __APPHEADERFILE_PNBAGX__

#include "JucePluginMain.h"
#include "Gui/BinaryData.h"

#if ! DONT_SET_USING_JUCE_NAMESPACE
// If your code uses a lot of JUCE classes, then this will obviously save you


+ 427
- 140
ports/obxd/source/PluginEditor.cpp View File

@@ -9,124 +9,24 @@ It contains the basic startup code for a Juce application.
*/
#include "PluginProcessor.h"
#include "PluginEditor.h"
#include "Gui/res.h"
#include <utility>
// #include "GUI/BinaryData.h"


//==============================================================================
ObxdAudioProcessorEditor::ObxdAudioProcessorEditor (ObxdAudioProcessor* ownerFilter)
: AudioProcessorEditor (ownerFilter)
{
// This is where our plugin's editor size is set.
setSize (1087, 442);
cutoffKnob = addNormalKnob(577,40,ownerFilter,CUTOFF,"Cutoff",0.4);
resonanceKnob = addNormalKnob(638,40,ownerFilter,RESONANCE,"Resonance",0);
filterEnvelopeAmtKnob = addNormalKnob(699,40,ownerFilter,ENVELOPE_AMT,"Envelope",0);
multimodeKnob = addTinyKnob(643,106,ownerFilter,MULTIMODE,"Multimode",0.5);

volumeKnob = addNormalKnob(53,120,ownerFilter,VOLUME,"Volume",0.4);
portamentoKnob = addNormalKnob(175,241,ownerFilter,PORTAMENTO,"Portamento",0);
osc1PitchKnob = addNormalKnob(271,40,ownerFilter,OSC1P,"Osc1Pitch",0);
pulseWidthKnob = addNormalKnob(334,40,ownerFilter,PW,"PW",0);
osc2PitchKnob = addNormalKnob(397,40,ownerFilter,OSC2P,"Osc2Pitch",0);

osc1MixKnob = addNormalKnob(490,40,ownerFilter,OSC1MIX,"Osc1",1);
osc2MixKnob = addNormalKnob(490,132,ownerFilter,OSC2MIX,"Osc2",1);
noiseMixKnob = addNormalKnob(490,224,ownerFilter,NOISEMIX,"Noise",0);

xmodKnob = addNormalKnob(334,168,ownerFilter,XMOD,"Xmod",0);
osc2DetuneKnob = addNormalKnob(334,104,ownerFilter,OSC2_DET,"Detune",0);

envPitchModKnob = addNormalKnob(376,232,ownerFilter,ENVPITCH,"PEnv",0);
brightnessKnob = addNormalKnob(291,232,ownerFilter,BRIGHTNESS,"Bri",1);

attackKnob = addNormalKnob(791,132,ownerFilter,LATK,"Atk",0);
decayKnob = addNormalKnob(853,132,ownerFilter,LDEC,"Dec",0);
sustainKnob = addNormalKnob(916,132,ownerFilter,LSUS,"Sus",1);
releaseKnob = addNormalKnob(980,132,ownerFilter,LREL,"Rel",0);

fattackKnob = addNormalKnob(791,40,ownerFilter,FATK,"Atk",0);
fdecayKnob = addNormalKnob(853,40,ownerFilter,FDEC,"Dec",0);
fsustainKnob = addNormalKnob(916,40,ownerFilter,FSUS,"Sus",1);
freleaseKnob = addNormalKnob(980,40,ownerFilter,FREL,"Rel",0);

lfoFrequencyKnob = addNormalKnob(576,207,ownerFilter,LFOFREQ,"Freq",0);
lfoAmt1Knob = addNormalKnob(640,207,ownerFilter,LFO1AMT,"Pitch",0);
lfoAmt2Knob = addNormalKnob(704,207,ownerFilter,LFO2AMT,"PWM",0);

lfoSinButton = addNormalTooglableButton(587,269,ownerFilter,LFOSINWAVE,"Sin");
lfoSquareButton = addNormalTooglableButton(587,323,ownerFilter,LFOSQUAREWAVE,"SQ");
lfoSHButton = addNormalTooglableButton(587,378,ownerFilter,LFOSHWAVE,"S&H");

lfoOsc1Button = addNormalTooglableButton(651,269,ownerFilter,LFOOSC1,"Osc1");
lfoOsc2Button = addNormalTooglableButton(651,323,ownerFilter,LFOOSC2,"Osc2");
lfoFilterButton = addNormalTooglableButton(651,378,ownerFilter,LFOFILTER,"Filt");

lfoPwm1Button = addNormalTooglableButton(714,269,ownerFilter,LFOPW1,"Osc1");
lfoPwm2Button = addNormalTooglableButton(714,323,ownerFilter,LFOPW2,"Osc2");

hardSyncButton = addNormalTooglableButton(282,178,ownerFilter,OSC2HS,"Sync");
osc1SawButton = addNormalTooglableButton(265,114,ownerFilter,OSC1Saw,"S");
osc2SawButton = addNormalTooglableButton(394,114,ownerFilter,OSC2Saw,"S");

osc1PulButton = addNormalTooglableButton(296,114,ownerFilter,OSC1Pul,"P");
osc2PulButton = addNormalTooglableButton(425,114,ownerFilter,OSC2Pul,"P");

pitchQuantButton = addNormalTooglableButton(407,178,ownerFilter,OSCQuantize,"Step");

filterBPBlendButton = addNormalTooglableButton(697,110,ownerFilter,BANDPASS,"Bp");
fourPoleButton = addNormalTooglableButton(728,110,ownerFilter,FOURPOLE,"24");
filterHQButton = addNormalTooglableButton(604,110,ownerFilter,FILTER_WARM,"HQ");

filterKeyFollowButton = addNormalTooglableButton(573,110,ownerFilter,FLT_KF,"Key");
unisonButton = addNormalTooglableButton(125,251,ownerFilter,UNISON,"Uni");
tuneKnob = addNormalKnob(114,120,ownerFilter,TUNE,"Tune",0.5);
voiceDetuneKnob =addNormalKnob(53,241,ownerFilter,UDET,"VoiceDet",0);

veloAmpEnvKnob = addNormalKnob(486,345,ownerFilter,VAMPENV,"VAE",0);
veloFltEnvKnob = addNormalKnob(428,345,ownerFilter,VFLTENV,"VFE",0);
transposeKnob = addNormalKnob(176,120,ownerFilter,OCTAVE,"Transpose",0.5);

pan1Knob = addTinyKnob(796,318,ownerFilter,PAN1,"1",0.5);
pan2Knob = addTinyKnob(858,318,ownerFilter,PAN2,"2",0.5);
pan3Knob = addTinyKnob(921,318,ownerFilter,PAN3,"3",0.5);
pan4Knob = addTinyKnob(984,318,ownerFilter,PAN4,"4",0.5);

pan5Knob = addTinyKnob(796,371,ownerFilter,PAN5,"5",0.5);
pan6Knob = addTinyKnob(858,371,ownerFilter,PAN6,"6",0.5);
pan7Knob = addTinyKnob(921,371,ownerFilter,PAN7,"7",0.5);
pan8Knob = addTinyKnob(984,371,ownerFilter,PAN8,"8",0.5);

bendOsc2OnlyButton = addNormalTooglableButton(321,354,ownerFilter,BENDOSC2,"Osc2");
bendRangeButton = addNormalTooglableButton(267,354,ownerFilter,BENDRANGE,"12");
asPlayedAllocButton = addNormalTooglableButton(65,372,ownerFilter,ASPLAYEDALLOCATION,"APA");

filterDetuneKnob = addTinyKnob(817,240,ownerFilter,FILTERDER,"Flt",0.2);
envelopeDetuneKnob = addTinyKnob(963,240,ownerFilter,ENVDER,"Env",0.2);
portamentoDetuneKnob = addTinyKnob(890,240,ownerFilter,PORTADER,"Port",0.2);

bendLfoRateKnob = addNormalKnob(364,345,ownerFilter,BENDLFORATE,"ModRate",0.4);

voiceSwitch = addNormalButtonList(172,321,38,ownerFilter,VOICE_COUNT,"VoiceCount",ImageCache::getFromMemory(res::voices_png,res::voices_pngSize));
voiceSwitch ->addChoise("1");
voiceSwitch ->addChoise("2");
voiceSwitch ->addChoise("3");
voiceSwitch ->addChoise("4");
voiceSwitch ->addChoise("5");
voiceSwitch ->addChoise("6");
voiceSwitch ->addChoise("7");
voiceSwitch ->addChoise("8");

legatoSwitch = addNormalButtonList(65,321,95,ownerFilter,LEGATOMODE,"Legato",ImageCache::getFromMemory(res::legato_png,res::legato_pngSize));
legatoSwitch ->addChoise("Keep all");
legatoSwitch ->addChoise("Keep fenv");
legatoSwitch ->addChoise("Keep aenv");
legatoSwitch ->addChoise("Retrig");

getFilter()->addChangeListener(this);

// update parameters
updateParametersFromFilter();
rebuildComponents();
}

ObxdAudioProcessorEditor::~ObxdAudioProcessorEditor()
{
getFilter()->removeChangeListener(this);

deleteAllChildren();
}

void ObxdAudioProcessorEditor::placeLabel(int x , int y , String text)
{
Label* lab = new Label();
@@ -135,23 +35,21 @@ void ObxdAudioProcessorEditor::placeLabel(int x , int y , String text)
lab->setText(text,dontSendNotification);lab->setInterceptsMouseClicks(false,true);
addAndMakeVisible(lab);
}

ButtonList* ObxdAudioProcessorEditor::addNormalButtonList(int x, int y,int width, ObxdAudioProcessor* filter, int parameter,String name,Image img)
{
ButtonList *bl = new ButtonList(img,32);
bl->setBounds(x, y, width, 32);
ButtonList *bl = new ButtonList(img,24);
bl->setBounds(x, y, width, 24);
//bl->setValue(filter->getParameter(parameter),dontSendNotification);
addAndMakeVisible(bl);
bl->addListener (this);
return bl;

}
ObxdAudioProcessorEditor::~ObxdAudioProcessorEditor()
{
getFilter()->removeChangeListener(this);
deleteAllChildren();
}

Knob* ObxdAudioProcessorEditor::addNormalKnob(int x , int y ,ObxdAudioProcessor* filter, int parameter,String name,float defval)
{
Knob* knob = new Knob(ImageCache::getFromMemory(res::knoblsd_png,res::knoblsd_pngSize),48);
Knob* knob = new Knob(ImageCache::getFromMemory(BinaryData::knoblsd_png,BinaryData::knoblsd_pngSize),48);
//Label* knobl = new Label();
knob->setSliderStyle(Slider::RotaryVerticalDrag);
knob->setTextBoxStyle(knob->NoTextBox,true,0,0);
@@ -159,6 +57,7 @@ Knob* ObxdAudioProcessorEditor::addNormalKnob(int x , int y ,ObxdAudioProcessor*
addAndMakeVisible(knob);
//addAndMakeVisible(knobl);
knob->setBounds(x, y, 48,48);
knob->setValue(filter->getParameter(parameter),dontSendNotification);
//knobl->setJustificationType(Justification::centred);
//knobl->setInterceptsMouseClicks(false,true);
//knobl->setBounds(x-10,y+40,60,10);
@@ -168,16 +67,40 @@ Knob* ObxdAudioProcessorEditor::addNormalKnob(int x , int y ,ObxdAudioProcessor*
knob->addListener (this);
return knob;
}

Knob* ObxdAudioProcessorEditor::addNormalKnobClassic(int x , int y ,ObxdAudioProcessor* filter, int parameter,String name,float defval)
{
Knob* knob = new Knob(ImageCache::getFromMemory(BinaryData::knoblsd_png,BinaryData::knoblsd_pngSize),48);
//Label* knobl = new Label();
knob->setSliderStyle(Slider::RotaryVerticalDrag);
knob->setTextBoxStyle(knob->NoTextBox,true,0,0);
knob->setRange(0,1);
addAndMakeVisible(knob);
//addAndMakeVisible(knobl);
knob->setBounds(x+2, y, 42,42);
knob->setValue(filter->getParameter(parameter),dontSendNotification);
//knobl->setJustificationType(Justification::centred);
//knobl->setInterceptsMouseClicks(false,true);
//knobl->setBounds(x-10,y+40,60,10);
//knobl->setText(name,dontSendNotification);
knob->setTextBoxIsEditable(false);
knob->setDoubleClickReturnValue(true,defval);
knob->addListener (this);
return knob;
}

Knob* ObxdAudioProcessorEditor::addTinyKnob(int x , int y ,ObxdAudioProcessor* filter, int parameter,String name,float defval)
{
Knob* knob = new Knob(ImageCache::getFromMemory(res::knobssd_png,res::knobssd_pngSize),42);
//Knob* knob = new Knob(ImageCache::getFromMemory(BinaryData::knobssd_png,BinaryData::knobssd_pngSize),42);
Knob* knob = new Knob(ImageCache::getFromMemory(BinaryData::knoblsd_png,BinaryData::knoblsd_pngSize),48);
//Label* knobl = new Label();
knob->setSliderStyle(Slider::RotaryVerticalDrag);
knob->setTextBoxStyle(knob->NoTextBox,true,0,0);
knob->setRange(0,1);
addAndMakeVisible(knob);
//addAndMakeVisible(knobl);
knob->setBounds(x, y, 42,42);
knob->setBounds(x, y, 36,36);
knob->setValue(filter->getParameter(parameter),dontSendNotification);
//knobl->setJustificationType(Justification::centred);
//knobl->setInterceptsMouseClicks(false,true);
//knobl->setBounds(x-10,y+25,50,10);
@@ -187,26 +110,314 @@ Knob* ObxdAudioProcessorEditor::addTinyKnob(int x , int y ,ObxdAudioProcessor* f
knob->addListener (this);
return knob;
}
TooglableButton* ObxdAudioProcessorEditor::addNormalTooglableButton(int x , int y , ObxdAudioProcessor* filter,int parameter,String name)

TooglableButton* ObxdAudioProcessorEditor::addNormalTooglableButton(int x , int y , ObxdAudioProcessor* filter,int parameter,String name)
{
TooglableButton* button = new TooglableButton(ImageCache::getFromMemory(res::button_png,res::button_pngSize));
TooglableButton* button = new TooglableButton(ImageCache::getFromMemory(BinaryData::button_png,BinaryData::button_pngSize));
// button->setButtonStyle(DrawableButton::ButtonStyle::ImageAboveTextLabel);
addAndMakeVisible(button);
button->setBounds(x,y,28,35);
button->setBounds(x,y,19,35);
button->setButtonText(name);
button->setValue(filter->getParameter(parameter),0);
button->addListener(this);
return button;
}
TooglableButton* ObxdAudioProcessorEditor::addTinyTooglableButton(int x , int y , ObxdAudioProcessor* filter,int parameter,String name)

TooglableButton* ObxdAudioProcessorEditor::addTinyTooglableButton(int x , int y , ObxdAudioProcessor* filter,int parameter,String name)
{
TooglableButton* button = new TooglableButton(ImageCache::getFromMemory(res::button_png,res::button_pngSize));
TooglableButton* button = new TooglableButton(ImageCache::getFromMemory(BinaryData::button_png,BinaryData::button_pngSize));
// button->setButtonStyle(DrawableButton::ButtonStyle::ImageAboveTextLabel);
addAndMakeVisible(button);
button->setBounds(x,y,20,20);
button->setButtonText(name);
button->setValue(filter->getParameter(parameter),0);
button->addListener(this);
return button;
}

ButtonList* ObxdAudioProcessorEditor::addNormalButtonListClassic(int x, int y,int width, ObxdAudioProcessor* filter, int parameter,String name,Image img)
{
ButtonList *bl = new ButtonList(img,32);
bl->setBounds(x, y, width, 32);
//bl->setValue(filter->getParameter(parameter),dontSendNotification);
addAndMakeVisible(bl);
bl->addListener (this);
return bl;
}

Knob* ObxdAudioProcessorEditor::addTinyKnobClassic(int x , int y ,ObxdAudioProcessor* filter, int parameter,String name,float defval)
{
Knob* knob = new Knob(ImageCache::getFromMemory(BinaryData::knoblsd_png,BinaryData::knoblsd_pngSize),48);
//Label* knobl = new Label();
knob->setSliderStyle(Slider::RotaryVerticalDrag);
knob->setTextBoxStyle(knob->NoTextBox,true,0,0);
knob->setRange(0,1);
addAndMakeVisible(knob);
//addAndMakeVisible(knobl);
knob->setBounds(x+3, y+3, 36,36);
knob->setValue(filter->getParameter(parameter),dontSendNotification);
//knobl->setJustificationType(Justification::centred);
//knobl->setInterceptsMouseClicks(false,true);
//knobl->setBounds(x-10,y+25,50,10);
//knobl->setText(name,dontSendNotification);
knob->setTextBoxIsEditable(false);
knob->setDoubleClickReturnValue(true,defval);
knob->addListener (this);
return knob;
}

TooglableButton* ObxdAudioProcessorEditor::addNormalTooglableButtonClassic(int x , int y , ObxdAudioProcessor* filter,int parameter,String name)
{
TooglableButton* button = new TooglableButton(ImageCache::getFromFile(skinFolder.getChildFile("button.png")));
// button->setButtonStyle(DrawableButton::ButtonStyle::ImageAboveTextLabel);
addAndMakeVisible(button);
button->setBounds(x,y,28,35);
button->setButtonText(name);
button->setValue(filter->getParameter(parameter),0);
button->addListener(this);
return button;
}

void ObxdAudioProcessorEditor::rebuildComponents()
{
ObxdAudioProcessor* ownerFilter = getFilter();

skinFolder = ownerFilter->getCurrentSkinFolder();
bool useClassicSkin = skinFolder.getChildFile("legato.png").existsAsFile();

ownerFilter->removeChangeListener(this);

deleteAllChildren();

if (! useClassicSkin)
{
// This is where our plugin's editor size is set.

setSize (1440, 450);
cutoffKnob = addNormalKnob(893,77,ownerFilter,CUTOFF,"Cutoff",0.4);
resonanceKnob = addNormalKnob(990,77,ownerFilter,RESONANCE,"Resonance",0);
filterEnvelopeAmtKnob = addNormalKnob(1088,77,ownerFilter,ENVELOPE_AMT,"Envelope",0);
multimodeKnob = addNormalKnob(990,167,ownerFilter,MULTIMODE,"Multimode",0.5);

volumeKnob = addNormalKnob(56,77,ownerFilter,VOLUME,"Volume",0.4);
portamentoKnob = addNormalKnob(188,77,ownerFilter,PORTAMENTO,"Portamento",0);
osc1PitchKnob = addNormalKnob(593,77,ownerFilter,OSC1P,"Osc1Pitch",0);
pulseWidthKnob = addNormalKnob(691,77,ownerFilter,PW,"PW",0);
osc2PitchKnob = addNormalKnob(788,77,ownerFilter,OSC2P,"Osc2Pitch",0);

osc1MixKnob = addNormalKnob(597,237,ownerFilter,OSC1MIX,"Osc1",1);
osc2MixKnob = addNormalKnob(788,237,ownerFilter,OSC2MIX,"Osc2",1);
noiseMixKnob = addNormalKnob(691,237,ownerFilter,NOISEMIX,"Noise",0);

xmodKnob = addNormalKnob(656,324,ownerFilter,XMOD,"Xmod",0);
osc2DetuneKnob = addNormalKnob(800,324,ownerFilter,OSC2_DET,"Detune",0);

envPitchModKnob = addNormalKnob(728,324,ownerFilter,ENVPITCH,"PEnv",0);
brightnessKnob = addNormalKnob(586,324,ownerFilter,BRIGHTNESS,"Bri",1);

attackKnob = addNormalKnob(1182,165,ownerFilter,LATK,"Atk",0);
decayKnob = addNormalKnob(1246,165,ownerFilter,LDEC,"Dec",0);
sustainKnob = addNormalKnob(1309,165,ownerFilter,LSUS,"Sus",1);
releaseKnob = addNormalKnob(1373,165,ownerFilter,LREL,"Rel",0);

fattackKnob = addNormalKnob(1182,75,ownerFilter,FATK,"Atk",0);
fdecayKnob = addNormalKnob(1246,75,ownerFilter,FDEC,"Dec",0);
fsustainKnob = addNormalKnob(1309,75,ownerFilter,FSUS,"Sus",1);
freleaseKnob = addNormalKnob(1373,75,ownerFilter,FREL,"Rel",0);

lfoFrequencyKnob = addNormalKnob(293,77,ownerFilter,LFOFREQ,"Freq",0);
lfoAmt1Knob = addNormalKnob(390,77,ownerFilter,LFO1AMT,"Pitch",0);
lfoAmt2Knob = addNormalKnob(488,77,ownerFilter,LFO2AMT,"PWM",0);

lfoSinButton = addNormalTooglableButton(309,162,ownerFilter,LFOSINWAVE,"Sin");
lfoSquareButton = addNormalTooglableButton(309,252,ownerFilter,LFOSQUAREWAVE,"SQ");
lfoSHButton = addNormalTooglableButton(309,335,ownerFilter,LFOSHWAVE,"S&H");

lfoOsc1Button = addNormalTooglableButton(406,162,ownerFilter,LFOOSC1,"Osc1");
lfoOsc2Button = addNormalTooglableButton(406,252,ownerFilter,LFOOSC2,"Osc2");
lfoFilterButton = addNormalTooglableButton(406,335,ownerFilter,LFOFILTER,"Filt");

lfoPwm1Button = addNormalTooglableButton(504,162,ownerFilter,LFOPW1,"Osc1");
lfoPwm2Button = addNormalTooglableButton(504,252,ownerFilter,LFOPW2,"Osc2");

hardSyncButton = addNormalTooglableButton(730,162,ownerFilter,OSC2HS,"Sync");
osc1SawButton = addNormalTooglableButton(587,162,ownerFilter,OSC1Saw,"S");
osc2SawButton = addNormalTooglableButton(782,162,ownerFilter,OSC2Saw,"S");

osc1PulButton = addNormalTooglableButton(632,162,ownerFilter,OSC1Pul,"P");
osc2PulButton = addNormalTooglableButton(827,162,ownerFilter,OSC2Pul,"P");

pitchQuantButton = addNormalTooglableButton(684,162,ownerFilter,OSCQuantize,"Step");

filterBPBlendButton = addNormalTooglableButton(1082,162,ownerFilter,BANDPASS,"Bp");
fourPoleButton = addNormalTooglableButton(1127,162,ownerFilter,FOURPOLE,"24");
filterHQButton = addNormalTooglableButton(932,162,ownerFilter,FILTER_WARM,"HQ");

filterKeyFollowButton = addNormalTooglableButton(887,162,ownerFilter,FLT_KF,"Key");
unisonButton = addNormalTooglableButton(205,162,ownerFilter,UNISON,"Uni");

tuneKnob = addNormalKnob(30,252,ownerFilter,TUNE,"Tune",0.5);
transposeKnob = addNormalKnob(90,252,ownerFilter,OCTAVE,"Transpose",0.5);

voiceDetuneKnob =addNormalKnob(188,252,ownerFilter,UDET,"VoiceDet",0);

bendLfoRateKnob = addTinyKnob(928,300,ownerFilter,BENDLFORATE,"ModRate",0.4);
veloFltEnvKnob = addTinyKnob(1013,300,ownerFilter,VFLTENV,"VFE",0);
veloAmpEnvKnob = addTinyKnob(1111,300,ownerFilter,VAMPENV,"VAE",0);

pan1Knob = addTinyKnob(914,368,ownerFilter,PAN1,"1",0.5);
pan2Knob = addTinyKnob(977,368,ownerFilter,PAN2,"2",0.5);
pan3Knob = addTinyKnob(1040,368,ownerFilter,PAN3,"3",0.5);
pan4Knob = addTinyKnob(1103,368,ownerFilter,PAN4,"4",0.5);

pan5Knob = addTinyKnob(1165,368,ownerFilter,PAN5,"5",0.5);
pan6Knob = addTinyKnob(1228,368,ownerFilter,PAN6,"6",0.5);
pan7Knob = addTinyKnob(1290,368,ownerFilter,PAN7,"7",0.5);
pan8Knob = addTinyKnob(1353,368,ownerFilter,PAN8,"8",0.5);

bendOsc2OnlyButton = addNormalTooglableButton(228,335,ownerFilter,BENDOSC2,"Osc2");
bendRangeButton = addNormalTooglableButton(183,335,ownerFilter,BENDRANGE,"12");
asPlayedAllocButton = addNormalTooglableButton(25,162,ownerFilter,ASPLAYEDALLOCATION,"APA");

filterDetuneKnob = addTinyKnob(1228,300,ownerFilter,FILTERDER,"Flt",0.2);
portamentoDetuneKnob = addTinyKnob(1291,300,ownerFilter,PORTADER,"Port",0.2);
envelopeDetuneKnob = addTinyKnob(1353,300,ownerFilter,ENVDER,"Env",0.2);

voiceSwitch = addNormalButtonList(124,338,17,ownerFilter,VOICE_COUNT,"VoiceCount",ImageCache::getFromMemory(BinaryData::voices_png,BinaryData::voices_pngSize));
voiceSwitch ->addChoise("1");
voiceSwitch ->addChoise("2");
voiceSwitch ->addChoise("3");
voiceSwitch ->addChoise("4");
voiceSwitch ->addChoise("5");
voiceSwitch ->addChoise("6");
voiceSwitch ->addChoise("7");
voiceSwitch ->addChoise("8");
voiceSwitch ->setValue(ownerFilter->getParameter(VOICE_COUNT),dontSendNotification);

legatoSwitch = addNormalButtonList(25,338,65,ownerFilter,LEGATOMODE,"Legato",ImageCache::getFromMemory(BinaryData::legato_png,BinaryData::legato_pngSize));
legatoSwitch ->addChoise("Keep All");
legatoSwitch ->addChoise("Keep Filter Envelope");
legatoSwitch ->addChoise("Keep Amplitude Envelope");
legatoSwitch ->addChoise("Retrig");
legatoSwitch ->setValue(ownerFilter->getParameter(LEGATOMODE),dontSendNotification);
}
else
{
// This is where our plugin's editor size is set.

setSize (1087, 442);
cutoffKnob = addNormalKnobClassic(577,40,ownerFilter,CUTOFF,"Cutoff",0.4);
resonanceKnob = addNormalKnobClassic(638,40,ownerFilter,RESONANCE,"Resonance",0);
filterEnvelopeAmtKnob = addNormalKnobClassic(699,40,ownerFilter,ENVELOPE_AMT,"Envelope",0);
multimodeKnob = addTinyKnobClassic(643,106,ownerFilter,MULTIMODE,"Multimode",0.5);

volumeKnob = addNormalKnobClassic(53,120,ownerFilter,VOLUME,"Volume",0.4);
portamentoKnob = addNormalKnobClassic(175,241,ownerFilter,PORTAMENTO,"Portamento",0);
osc1PitchKnob = addNormalKnobClassic(271,40,ownerFilter,OSC1P,"Osc1Pitch",0);
pulseWidthKnob = addNormalKnobClassic(334,40,ownerFilter,PW,"PW",0);
osc2PitchKnob = addNormalKnobClassic(397,40,ownerFilter,OSC2P,"Osc2Pitch",0);

osc1MixKnob = addNormalKnobClassic(490,40,ownerFilter,OSC1MIX,"Osc1",1);
osc2MixKnob = addNormalKnobClassic(490,132,ownerFilter,OSC2MIX,"Osc2",1);
noiseMixKnob = addNormalKnobClassic(490,224,ownerFilter,NOISEMIX,"Noise",0);

xmodKnob = addNormalKnobClassic(334,168,ownerFilter,XMOD,"Xmod",0);
osc2DetuneKnob = addNormalKnobClassic(334,104,ownerFilter,OSC2_DET,"Detune",0);

envPitchModKnob = addNormalKnobClassic(376,232,ownerFilter,ENVPITCH,"PEnv",0);
brightnessKnob = addNormalKnobClassic(291,232,ownerFilter,BRIGHTNESS,"Bri",1);

attackKnob = addNormalKnobClassic(791,132,ownerFilter,LATK,"Atk",0);
decayKnob = addNormalKnobClassic(853,132,ownerFilter,LDEC,"Dec",0);
sustainKnob = addNormalKnobClassic(916,132,ownerFilter,LSUS,"Sus",1);
releaseKnob = addNormalKnobClassic(980,132,ownerFilter,LREL,"Rel",0);

fattackKnob = addNormalKnobClassic(791,40,ownerFilter,FATK,"Atk",0);
fdecayKnob = addNormalKnobClassic(853,40,ownerFilter,FDEC,"Dec",0);
fsustainKnob = addNormalKnobClassic(916,40,ownerFilter,FSUS,"Sus",1);
freleaseKnob = addNormalKnobClassic(980,40,ownerFilter,FREL,"Rel",0);

lfoFrequencyKnob = addNormalKnobClassic(576,207,ownerFilter,LFOFREQ,"Freq",0);
lfoAmt1Knob = addNormalKnobClassic(640,207,ownerFilter,LFO1AMT,"Pitch",0);
lfoAmt2Knob = addNormalKnobClassic(704,207,ownerFilter,LFO2AMT,"PWM",0);

lfoSinButton = addNormalTooglableButtonClassic(587,269,ownerFilter,LFOSINWAVE,"Sin");
lfoSquareButton = addNormalTooglableButtonClassic(587,323,ownerFilter,LFOSQUAREWAVE,"SQ");
lfoSHButton = addNormalTooglableButtonClassic(587,378,ownerFilter,LFOSHWAVE,"S&H");

lfoOsc1Button = addNormalTooglableButtonClassic(651,269,ownerFilter,LFOOSC1,"Osc1");
lfoOsc2Button = addNormalTooglableButtonClassic(651,323,ownerFilter,LFOOSC2,"Osc2");
lfoFilterButton = addNormalTooglableButtonClassic(651,378,ownerFilter,LFOFILTER,"Filt");

lfoPwm1Button = addNormalTooglableButtonClassic(714,269,ownerFilter,LFOPW1,"Osc1");
lfoPwm2Button = addNormalTooglableButtonClassic(714,323,ownerFilter,LFOPW2,"Osc2");

hardSyncButton = addNormalTooglableButtonClassic(282,178,ownerFilter,OSC2HS,"Sync");
osc1SawButton = addNormalTooglableButtonClassic(265,114,ownerFilter,OSC1Saw,"S");
osc2SawButton = addNormalTooglableButtonClassic(394,114,ownerFilter,OSC2Saw,"S");

osc1PulButton = addNormalTooglableButtonClassic(296,114,ownerFilter,OSC1Pul,"P");
osc2PulButton = addNormalTooglableButtonClassic(425,114,ownerFilter,OSC2Pul,"P");

pitchQuantButton = addNormalTooglableButtonClassic(407,178,ownerFilter,OSCQuantize,"Step");

filterBPBlendButton = addNormalTooglableButtonClassic(697,110,ownerFilter,BANDPASS,"Bp");
fourPoleButton = addNormalTooglableButtonClassic(728,110,ownerFilter,FOURPOLE,"24");
filterHQButton = addNormalTooglableButtonClassic(604,110,ownerFilter,FILTER_WARM,"HQ");

filterKeyFollowButton = addNormalTooglableButtonClassic(573,110,ownerFilter,FLT_KF,"Key");
unisonButton = addNormalTooglableButtonClassic(125,251,ownerFilter,UNISON,"Uni");
tuneKnob = addNormalKnobClassic(114,120,ownerFilter,TUNE,"Tune",0.5);
voiceDetuneKnob =addNormalKnobClassic(53,241,ownerFilter,UDET,"VoiceDet",0);

veloAmpEnvKnob = addNormalKnobClassic(486,345,ownerFilter,VAMPENV,"VAE",0);
veloFltEnvKnob = addNormalKnobClassic(428,345,ownerFilter,VFLTENV,"VFE",0);
transposeKnob = addNormalKnobClassic(176,120,ownerFilter,OCTAVE,"Transpose",0.5);

pan1Knob = addTinyKnobClassic(796,318,ownerFilter,PAN1,"1",0.5);
pan2Knob = addTinyKnobClassic(858,318,ownerFilter,PAN2,"2",0.5);
pan3Knob = addTinyKnobClassic(921,318,ownerFilter,PAN3,"3",0.5);
pan4Knob = addTinyKnobClassic(984,318,ownerFilter,PAN4,"4",0.5);

pan5Knob = addTinyKnobClassic(796,371,ownerFilter,PAN5,"5",0.5);
pan6Knob = addTinyKnobClassic(858,371,ownerFilter,PAN6,"6",0.5);
pan7Knob = addTinyKnobClassic(921,371,ownerFilter,PAN7,"7",0.5);
pan8Knob = addTinyKnobClassic(984,371,ownerFilter,PAN8,"8",0.5);

bendOsc2OnlyButton = addNormalTooglableButtonClassic(321,354,ownerFilter,BENDOSC2,"Osc2");
bendRangeButton = addNormalTooglableButtonClassic(267,354,ownerFilter,BENDRANGE,"12");
asPlayedAllocButton = addNormalTooglableButtonClassic(65,372,ownerFilter,ASPLAYEDALLOCATION,"APA");

filterDetuneKnob = addTinyKnobClassic(817,240,ownerFilter,FILTERDER,"Flt",0.2);
envelopeDetuneKnob = addTinyKnobClassic(963,240,ownerFilter,ENVDER,"Env",0.2);
portamentoDetuneKnob = addTinyKnobClassic(890,240,ownerFilter,PORTADER,"Port",0.2);

bendLfoRateKnob = addNormalKnobClassic(364,345,ownerFilter,BENDLFORATE,"ModRate",0.4);

voiceSwitch = addNormalButtonListClassic(172,321,38,ownerFilter,VOICE_COUNT,"VoiceCount",ImageCache::getFromFile(skinFolder.getChildFile("voices.png")));
voiceSwitch ->addChoise("1");
voiceSwitch ->addChoise("2");
voiceSwitch ->addChoise("3");
voiceSwitch ->addChoise("4");
voiceSwitch ->addChoise("5");
voiceSwitch ->addChoise("6");
voiceSwitch ->addChoise("7");
voiceSwitch ->addChoise("8");
voiceSwitch ->setValue(ownerFilter->getParameter(VOICE_COUNT),dontSendNotification);

legatoSwitch = addNormalButtonListClassic(65,321,95,ownerFilter,LEGATOMODE,"Legato",ImageCache::getFromFile(skinFolder.getChildFile("legato.png")));
legatoSwitch ->addChoise("Keep all");
legatoSwitch ->addChoise("Keep fenv");
legatoSwitch ->addChoise("Keep aenv");
legatoSwitch ->addChoise("Retrig");
legatoSwitch ->setValue(ownerFilter->getParameter(LEGATOMODE),dontSendNotification);
}

ownerFilter->addChangeListener(this);

repaint();
}

void ObxdAudioProcessorEditor::buttonClicked(Button * b)
{
TooglableButton* tb = (TooglableButton*)(b);
@@ -240,6 +451,7 @@ void ObxdAudioProcessorEditor::buttonClicked(Button * b)
{};

}

void ObxdAudioProcessorEditor::comboBoxChanged (ComboBox* cb)
{
ButtonList* bl = (ButtonList*)(cb);
@@ -250,6 +462,7 @@ void ObxdAudioProcessorEditor::comboBoxChanged (ComboBox* cb)
handleCParam(legatoSwitch,LEGATOMODE)
{};
}

void ObxdAudioProcessorEditor::sliderValueChanged (Slider* c)
{
ObxdAudioProcessor* flt = getFilter();
@@ -311,8 +524,6 @@ void ObxdAudioProcessorEditor::sliderValueChanged (Slider* c)
//magic crystal
{};



//else if(c == cutoffKnob)
//{sp(CUTOFF);}
//else if(c == resonanceKnob)
@@ -326,19 +537,16 @@ void ObxdAudioProcessorEditor::sliderValueChanged (Slider* c)
//else if (c == osc2PitchKnob)
//{sp(OSC2P);}
}

//==============================================================================
void ObxdAudioProcessorEditor::changeListenerCallback (ChangeBroadcaster* source)
{
updateParametersFromFilter();
}

void ObxdAudioProcessorEditor::updateParametersFromFilter()
{
ObxdAudioProcessor* filter = getFilter();

float pr[PARAM_COUNT];
filter->getCallbackLock().enter();
for(int i = 0 ; i < PARAM_COUNT;++i)
pr[i] = filter->programs.currentProgramPtr->values[i];
pr[i] = filter->getPrograms().currentProgramPtr->values[i];
filter->getCallbackLock().exit();
#define rn(T,P) (T->setValue(pr[P],dontSendNotification));
rn(cutoffKnob,CUTOFF)
@@ -422,14 +630,93 @@ void ObxdAudioProcessorEditor::updateParametersFromFilter()
rn(voiceSwitch,VOICE_COUNT)
rn(legatoSwitch,LEGATOMODE)
rn(asPlayedAllocButton,ASPLAYEDALLOCATION)
}

void ObxdAudioProcessorEditor::mouseUp(const MouseEvent& e)
{
if (e.mods.isRightButtonDown() || e.mods.isCommandDown())
{
PopupMenu menu;
PopupMenu skinMenu;
PopupMenu bankMenu;

Array<File> skins;
const Array<File>& banks = getFilter()->getBankFiles();

int skinStart = 0;
{
DirectoryIterator it(getFilter()->getSkinFolder(), false, "*", File::findDirectories);
while (it.next())
{
skins.add(it.getFile());
}

for (int i = 0; i < skins.size(); ++i)
{
const File skin = skins.getUnchecked(i);
skinMenu.addItem(i + skinStart + 1, skin.getFileName(), true, skin.getFileName() == skinFolder.getFileName());
}

menu.addSubMenu("Skins", skinMenu);
}

int bankStart = 1000;
{
const String currentBank = getFilter()->getCurrentBankFile().getFileName();

for (int i = 0; i < banks.size(); ++i)
{
const File bank = banks.getUnchecked(i);
bankMenu.addItem(i + bankStart + 1, bank.getFileName(), true, bank.getFileName() == currentBank);
}

menu.addSubMenu("Banks", bankMenu);
}

const Point<int> pos = e.getMouseDownScreenPosition();

int result = menu.showAt(Rectangle<int>(pos.getX(), pos.getY(), 1, 1));
if (result >= (skinStart + 1) && result <= (skinStart + skins.size()))
{
result -= 1;
result -= skinStart;

const File newSkinFolder = skins.getUnchecked(result);
getFilter()->setCurrentSkinFolder(newSkinFolder.getFileName());

rebuildComponents();
}
else if (result >= (bankStart + 1) && result <= (bankStart + banks.size()))
{
result -= 1;
result -= bankStart;

const File bankFile = banks.getUnchecked(result);
getFilter()->loadFromFXBFile(bankFile);
}
}
}
void ObxdAudioProcessorEditor::paint (Graphics& g)

void ObxdAudioProcessorEditor::paint(Graphics& g)
{
g.fillAll (Colours::white);

const Image image = ImageCache::getFromMemory(res::background_png,res::background_pngSize);
g.drawImage (image,
0, 0, image.getWidth(), image.getHeight(),
0, 0, image.getWidth(), image.getHeight());
}
const File mainFile(skinFolder.getChildFile("main.png"));

if (skinFolder.exists() && mainFile.exists())
{
const Image image = ImageCache::getFromFile(mainFile);

g.drawImage (image,
0, 0, image.getWidth(), image.getHeight(),
0, 0, image.getWidth(), image.getHeight());
}
else
{
const Image image = ImageCache::getFromMemory(BinaryData::main_png, BinaryData::main_pngSize);

g.drawImage (image,
0, 0, image.getWidth(), image.getHeight(),
0, 0, image.getWidth(), image.getHeight());
}
}

+ 25
- 30
ports/obxd/source/PluginEditor.h View File

@@ -22,29 +22,25 @@
//==============================================================================
/**
*/
class ObxdAudioProcessorEditor :
class ObxdAudioProcessorEditor :
public AudioProcessorEditor,
public ChangeListener,
public Slider::Listener,
public Button::Listener,
public ComboBox::Listener//,
// public AudioProcessorListener

// public AudioProcessorListener,
public ChangeListener,
public Slider::Listener,
public Button::Listener,
public ComboBox::Listener
{
public:
ObxdAudioProcessorEditor (ObxdAudioProcessor* ownerFilter);
ObxdAudioProcessorEditor(ObxdAudioProcessor* ownerFilter);
~ObxdAudioProcessorEditor();

//==============================================================================
/** Our demo filter is a ChangeBroadcaster, and will call us back when one of
its parameters changes.
*/
void changeListenerCallback (ChangeBroadcaster* source);
int changeListenerCallback (void*){return 0;};


void mouseUp(const MouseEvent& e);
void paint(Graphics& g);

//==============================================================================
void changeListenerCallback (ChangeBroadcaster* source);

private:
Knob* addNormalKnob(int x , int y ,ObxdAudioProcessor* filter, int parameter,String name,float defval);
Knob* addTinyKnob(int x , int y ,ObxdAudioProcessor* filter, int parameter,String name,float defval);
void placeLabel(int x , int y,String text);
@@ -56,14 +52,17 @@ public:
void buttonClicked (Button *);
void comboBoxChanged(ComboBox*);

void updateParametersFromFilter();
Knob* addNormalKnobClassic(int x , int y ,ObxdAudioProcessor* filter, int parameter,String name,float defval);
Knob* addTinyKnobClassic(int x , int y ,ObxdAudioProcessor* filter, int parameter,String name,float defval);
TooglableButton* addNormalTooglableButtonClassic(int x , int y , ObxdAudioProcessor* filter,int parameter,String name);
ButtonList* addNormalButtonListClassic(int x , int y ,int width, ObxdAudioProcessor* filter,int parameter,String name,Image img);

//==============================================================================
/** Standard Juce paint callback. */
void paint (Graphics& g);
void rebuildComponents();

/** Standard Juce resize callback. */
//void resized();
//==============================================================================
ObxdAudioProcessor* getFilter() noexcept { return (ObxdAudioProcessor*)getAudioProcessor();}

//==============================================================================
Knob* cutoffKnob,*resonanceKnob,*osc1PitchKnob,*osc2PitchKnob,*osc2DetuneKnob,*volumeKnob,
*portamentoKnob,*voiceDetuneKnob,*filterEnvelopeAmtKnob,*pulseWidthKnob,*xmodKnob,*multimodeKnob,*attackKnob,*decayKnob,*sustainKnob,*releaseKnob,
*fattackKnob,*fdecayKnob,*fsustainKnob,*freleaseKnob,*osc1MixKnob,*osc2MixKnob,*noiseMixKnob,
@@ -72,22 +71,18 @@ public:
*lfoFrequencyKnob,*lfoAmt1Knob,*lfoAmt2Knob,
*pan1Knob,*pan2Knob,*pan3Knob,*pan4Knob,*pan5Knob,*pan6Knob,*pan7Knob,*pan8Knob,
*brightnessKnob,*envPitchModKnob,
*bendLfoRateKnob
,*veloAmpEnvKnob,*veloFltEnvKnob,*transposeKnob;
*bendLfoRateKnob,*veloAmpEnvKnob,*veloFltEnvKnob,*transposeKnob;

TooglableButton* hardSyncButton,*osc1SawButton,*osc2SawButton,*osc1PulButton,*osc2PulButton,*filterKeyFollowButton,*unisonButton,*pitchQuantButton,
*filterHQButton,*filterBPBlendButton,
*lfoSinButton,*lfoSquareButton,*lfoSHButton,*lfoOsc1Button,*lfoOsc2Button,*lfoFilterButton,
*lfoPwm1Button,*lfoPwm2Button,
*bendRangeButton,*bendOsc2OnlyButton,
*fourPoleButton,*asPlayedAllocButton;
*fourPoleButton,*asPlayedAllocButton;

ButtonList *voiceSwitch,*legatoSwitch;
//==============================================================================
// This is just a standard Juce paint method...
// void paint (Graphics& g);
ObxdAudioProcessor* getFilter() noexcept { return (ObxdAudioProcessor*)getAudioProcessor();}
};

File skinFolder;
};

#endif // PLUGINEDITOR_H_INCLUDED

+ 439
- 174
ports/obxd/source/PluginProcessor.cpp View File

@@ -13,33 +13,51 @@ It contains the basic startup code for a Juce application.

//==============================================================================
#define S(T) (juce::String(T))
ObxdAudioProcessor::ObxdAudioProcessor() : programs()

//==============================================================================
ObxdAudioProcessor::ObxdAudioProcessor()
: programs()
, configLock("__" JucePlugin_Name "ConfigLock__")
{
synth = new SynthEngine();
synth->setSampleRate(44100);
isHostAutomatedChange = true;

synth.setSampleRate(44100);

PropertiesFile::Options options;
options.applicationName = JucePlugin_Name;
options.storageFormat = PropertiesFile::storeAsXML;
options.millisecondsBeforeSaving = 2500;
options.processLock = &configLock;
config = new PropertiesFile(getDocumentFolder().getChildFile("Settings.xml"), options);

currentSkin = config->containsKey("skin") ? config->getValue("skin") : "discoDSP Grey";
currentBank = "Init";

scanAndUpdateBanks();
initAllParams();
rnd = Random();
nextMidi = midiMsg = NULL;

if (bankFiles.size() > 0)
{
loadFromFXBFile(bankFiles[0]);
}
}

ObxdAudioProcessor::~ObxdAudioProcessor()
{
delete synth;
delete nextMidi;
delete midiMsg;
config->saveIfNeeded();
config = nullptr;
}

//==============================================================================
void ObxdAudioProcessor::initAllParams()
{
for(int i = 0 ; i < PARAM_COUNT;i++)
setParameter(i,programs.currentProgramPtr->values[i]);
}
//==============================================================================
const String ObxdAudioProcessor::getName() const
{
return JucePlugin_Name;
for (int i = 0 ; i < PARAM_COUNT; i++)
{
setParameter(i, programs.currentProgramPtr->values[i]);
}
}

//==============================================================================
int ObxdAudioProcessor::getNumParameters()
{
return PARAM_COUNT;
@@ -55,223 +73,271 @@ void ObxdAudioProcessor::setParameter (int index, float newValue)
programs.currentProgramPtr->values[index] = newValue;
switch(index)
{
case SELF_OSC_PUSH:
synth.processSelfOscPush(newValue);
break;
case PW_ENV_BOTH:
synth.processPwEnvBoth(newValue);
break;
case PW_OSC2_OFS:
synth.processPwOfs(newValue);
break;
case ENV_PITCH_BOTH:
synth.processPitchModBoth(newValue);
break;
case FENV_INVERT:
synth.processInvertFenv(newValue);
break;
case LEVEL_DIF:
synth.processLoudnessDetune(newValue);
break;
case PW_ENV:
synth.processPwEnv(newValue);
break;
case LFO_SYNC:
synth.procLfoSync(newValue);
break;
case ECONOMY_MODE:
synth.procEconomyMode(newValue);
break;
case VAMPENV:
synth->procAmpVelocityAmount(newValue);
synth.procAmpVelocityAmount(newValue);
break;
case VFLTENV:
synth->procFltVelocityAmount(newValue);
synth.procFltVelocityAmount(newValue);
break;
case ASPLAYEDALLOCATION:
synth->procAsPlayedAlloc(newValue);
synth.procAsPlayedAlloc(newValue);
break;
case BENDLFORATE:
synth->procModWheelFrequency(newValue);
synth.procModWheelFrequency(newValue);
break;
case FOURPOLE:
synth->processFourPole(newValue);
synth.processFourPole(newValue);
break;
case LEGATOMODE:
synth->processLegatoMode(newValue);
synth.processLegatoMode(newValue);
break;
case ENVPITCH:
synth->processEnvelopeToPitch(newValue);
synth.processEnvelopeToPitch(newValue);
break;
case OSCQuantize:
synth->processPitchQuantization(newValue);
synth.processPitchQuantization(newValue);
break;
case VOICE_COUNT:
synth->setVoiceCount(newValue);
synth.setVoiceCount(newValue);
break;
case BANDPASS:
synth->processBandpassSw(newValue);
synth.processBandpassSw(newValue);
break;
case FILTER_WARM:
synth->processOversampling(newValue);
synth.processOversampling(newValue);
break;
case BENDOSC2:
synth->procPitchWheelOsc2Only(newValue);
synth.procPitchWheelOsc2Only(newValue);
break;
case BENDRANGE:
synth->procPitchWheelAmount(newValue);
synth.procPitchWheelAmount(newValue);
break;
case NOISEMIX:
synth->processNoiseMix(newValue);
synth.processNoiseMix(newValue);
break;
case OCTAVE:
synth->processOctave(newValue);
synth.processOctave(newValue);
break;
case TUNE:
synth->processTune(newValue);
synth.processTune(newValue);
break;
case BRIGHTNESS:
synth->processBrightness(newValue);
synth.processBrightness(newValue);
break;
case MULTIMODE:
synth->processMultimode(newValue);
synth.processMultimode(newValue);
break;
case LFOFREQ:
synth->processLfoFrequency(newValue);
synth.processLfoFrequency(newValue);
break;
case LFO1AMT:
synth->processLfoAmt1(newValue);
synth.processLfoAmt1(newValue);
break;
case LFO2AMT:
synth->processLfoAmt2(newValue);
synth.processLfoAmt2(newValue);
break;
case LFOSINWAVE:
synth->processLfoSine(newValue);
synth.processLfoSine(newValue);
break;
case LFOSQUAREWAVE:
synth->processLfoSquare(newValue);
synth.processLfoSquare(newValue);
break;
case LFOSHWAVE:
synth->processLfoSH(newValue);
synth.processLfoSH(newValue);
break;
case LFOFILTER:
synth->processLfoFilter(newValue);
synth.processLfoFilter(newValue);
break;
case LFOOSC1:
synth->processLfoOsc1(newValue);
synth.processLfoOsc1(newValue);
break;
case LFOOSC2:
synth->processLfoOsc2(newValue);
synth.processLfoOsc2(newValue);
break;
case LFOPW1:
synth->processLfoPw1(newValue);
synth.processLfoPw1(newValue);
break;
case LFOPW2:
synth->processLfoPw2(newValue);
synth.processLfoPw2(newValue);
break;
case PORTADER:
synth->processPortamentoDetune(newValue);
synth.processPortamentoDetune(newValue);
break;
case FILTERDER:
synth->processFilterDetune(newValue);
synth.processFilterDetune(newValue);
break;
case ENVDER:
synth->processEnvelopeDetune(newValue);
synth.processEnvelopeDetune(newValue);
break;
case XMOD:
synth->processOsc2Xmod(newValue);
synth.processOsc2Xmod(newValue);
break;
case OSC2HS:
synth->processOsc2HardSync(newValue);
synth.processOsc2HardSync(newValue);
break;
case OSC2P:
synth->processOsc2Pitch(newValue);
synth.processOsc2Pitch(newValue);
break;
case OSC1P:
synth->processOsc1Pitch(newValue);
synth.processOsc1Pitch(newValue);
break;
case PORTAMENTO:
synth->processPortamento(newValue);
synth.processPortamento(newValue);
break;
case UNISON:
synth->processUnison(newValue);
synth.processUnison(newValue);
break;
case FLT_KF:
synth->processFilterKeyFollow(newValue);
synth.processFilterKeyFollow(newValue);
break;
case OSC1MIX:
synth->processOsc1Mix(newValue);
synth.processOsc1Mix(newValue);
break;
case OSC2MIX:
synth->processOsc2Mix(newValue);
synth.processOsc2Mix(newValue);
break;
case PW:
synth->processPulseWidth(newValue);
synth.processPulseWidth(newValue);
break;
case OSC1Saw:
synth->processOsc1Saw(newValue);
synth.processOsc1Saw(newValue);
break;
case OSC2Saw:
synth->processOsc2Saw(newValue);
synth.processOsc2Saw(newValue);
break;
case OSC1Pul:
synth->processOsc1Pulse(newValue);
synth.processOsc1Pulse(newValue);
break;
case OSC2Pul:
synth->processOsc2Pulse(newValue);
synth.processOsc2Pulse(newValue);
break;
case VOLUME:
synth->processVolume(newValue);
synth.processVolume(newValue);
break;
case UDET:
synth->processDetune(newValue);
synth.processDetune(newValue);
break;
case OSC2_DET:
synth->processOsc2Det(newValue);
synth.processOsc2Det(newValue);
break;
case CUTOFF:
synth->processCutoff(newValue);
synth.processCutoff(newValue);
break;
case RESONANCE:
synth->processResonance(newValue);
synth.processResonance(newValue);
break;
case ENVELOPE_AMT:
synth->processFilterEnvelopeAmt(newValue);
synth.processFilterEnvelopeAmt(newValue);
break;
case LATK:
synth->processLoudnessEnvelopeAttack(newValue);
synth.processLoudnessEnvelopeAttack(newValue);
break;
case LDEC:
synth->processLoudnessEnvelopeDecay(newValue);
synth.processLoudnessEnvelopeDecay(newValue);
break;
case LSUS:
synth->processLoudnessEnvelopeSustain(newValue);
synth.processLoudnessEnvelopeSustain(newValue);
break;
case LREL:
synth->processLoudnessEnvelopeRelease(newValue);
synth.processLoudnessEnvelopeRelease(newValue);
break;
case FATK:
synth->processFilterEnvelopeAttack(newValue);
synth.processFilterEnvelopeAttack(newValue);
break;
case FDEC:
synth->processFilterEnvelopeDecay(newValue);
synth.processFilterEnvelopeDecay(newValue);
break;
case FSUS:
synth->processFilterEnvelopeSustain(newValue);
synth.processFilterEnvelopeSustain(newValue);
break;
case FREL:
synth->processFilterEnvelopeRelease(newValue);
synth.processFilterEnvelopeRelease(newValue);
break;
case PAN1:
synth->processPan(newValue,1);
synth.processPan(newValue,1);
break;
case PAN2:
synth->processPan(newValue,2);
synth.processPan(newValue,2);
break;
case PAN3:
synth->processPan(newValue,3);
synth.processPan(newValue,3);
break;
case PAN4:
synth->processPan(newValue,4);
synth.processPan(newValue,4);
break;
case PAN5:
synth->processPan(newValue,5);
synth.processPan(newValue,5);
break;
case PAN6:
synth->processPan(newValue,6);
synth.processPan(newValue,6);
break;
case PAN7:
synth->processPan(newValue,7);
synth.processPan(newValue,7);
break;
case PAN8:
synth->processPan(newValue,8);
synth.processPan(newValue,8);
break;
}
sendChangeMessage();
//DIRTY HACK
//This should be checked to avoid stalling on gui update
//It is needed because some hosts do wierd stuff
if(isHostAutomatedChange)
sendChangeMessage();
}

const String ObxdAudioProcessor::getParameterName (int index)
{
switch(index)
{
case UNDEFINED:
return S("unused");
case UNDEFINED2:
return S("unused2");
case UNDEFINED3:
return S("unused3");
case SELF_OSC_PUSH:
return S("SelfOscPush");
case ENV_PITCH_BOTH:
return S("EnvPitchBoth");
case FENV_INVERT:
return S("FenvInvert");
case PW_OSC2_OFS:
return S("PwOfs");
case LEVEL_DIF:
return S("LevelDif");
case PW_ENV_BOTH:
return S("PwEnvBoth");
case PW_ENV:
return S("PwEnv");
case LFO_SYNC:
return S("LfoSync");
case ECONOMY_MODE:
return S("EconomyMode");
case UNUSED_1:
return S("Unused 1");
case UNUSED_2:
return S("Unused 2");
case VAMPENV:
return S("VAmpFactor");
case VFLTENV:
@@ -417,6 +483,12 @@ const String ObxdAudioProcessor::getParameterText (int index)
return String(programs.currentProgramPtr->values[index],2);
}

//==============================================================================
const String ObxdAudioProcessor::getName() const
{
return JucePlugin_Name;
}

const String ObxdAudioProcessor::getInputChannelName (int channelIndex) const
{
return String (channelIndex + 1);
@@ -464,6 +536,8 @@ double ObxdAudioProcessor::getTailLengthSeconds() const
{
return 0.0;
}

//==============================================================================
int ObxdAudioProcessor::getNumPrograms()
{
return PROGRAMCOUNT;
@@ -478,8 +552,12 @@ void ObxdAudioProcessor::setCurrentProgram (int index)
{
programs.currentProgram = index;
programs.currentProgramPtr = programs.programs + programs.currentProgram;
isHostAutomatedChange = false;
for(int i = 0 ; i < PARAM_COUNT;i++)
setParameter(i,programs.currentProgramPtr->values[i]);
isHostAutomatedChange = true;
sendChangeMessage();
updateHostDisplay();
}

const String ObxdAudioProcessor::getProgramName (int index)
@@ -497,174 +575,361 @@ void ObxdAudioProcessor::prepareToPlay (double sampleRate, int samplesPerBlock)
{
// Use this method as the place to do any pre-playback
// initialisation that you need..
delete nextMidi;
delete midiMsg;
nextMidi= new MidiMessage(0xF0);
midiMsg = new MidiMessage(0xF0);
synth->setSampleRate(sampleRate);
nextMidi = MidiMessage(0xF0);
midiMsg = MidiMessage(0xF0);
synth.setSampleRate(sampleRate);
}

void ObxdAudioProcessor::releaseResources()
{
delete nextMidi;
delete midiMsg;
nextMidi = midiMsg = NULL;

}

inline void ObxdAudioProcessor::processMidiPerSample(MidiBuffer::Iterator* iter,const int samplePos)
{
while (getNextEvent(iter, samplePos))
{
if(midiMsg->isNoteOn())
if(midiMsg.isNoteOn())
{
synth->procNoteOn(midiMsg->getNoteNumber(),midiMsg->getFloatVelocity());
synth.procNoteOn(midiMsg.getNoteNumber(),midiMsg.getFloatVelocity());
}
if (midiMsg->isNoteOff())
if (midiMsg.isNoteOff())
{
synth->procNoteOff(midiMsg->getNoteNumber());
synth.procNoteOff(midiMsg.getNoteNumber());
}
if(midiMsg->isPitchWheel())
if(midiMsg.isPitchWheel())
{
// [0..16383] center = 8192;
synth->procPitchWheel((midiMsg->getPitchWheelValue()-8192) / 8192.0);
synth.procPitchWheel((midiMsg.getPitchWheelValue()-8192) / 8192.0);
}
if(midiMsg->isController() && midiMsg->getControllerNumber()==1)
if(midiMsg.isController() && midiMsg.getControllerNumber()==1)
synth.procModWheel(midiMsg.getControllerValue() / 127.0);
if(midiMsg.isSustainPedalOn())
{
synth->procModWheel(midiMsg->getControllerValue() / 127.0);
synth.sustainOn();
}
if(midiMsg->isSustainPedalOn())
if(midiMsg.isSustainPedalOff() || midiMsg.isAllNotesOff()||midiMsg.isAllSoundOff())
{
synth->sustainOn();
synth.sustainOff();
}
if(midiMsg->isSustainPedalOff() || midiMsg->isAllNotesOff()||midiMsg->isAllSoundOff())
if(midiMsg.isAllNotesOff())
{
synth->sustainOff();
synth.allNotesOff();
}
if(midiMsg->isAllNotesOff())
if(midiMsg.isAllSoundOff())
{
synth->allNotesOff();
}
if(midiMsg->isAllSoundOff())
{
synth->allSoundOff();
synth.allSoundOff();
}

}
}

bool ObxdAudioProcessor::getNextEvent(MidiBuffer::Iterator* iter,const int samplePos)
{
if (hasMidiMessage && midiEventPos <= samplePos)
{
*midiMsg = *nextMidi;
hasMidiMessage = iter->getNextEvent(*nextMidi, midiEventPos);
midiMsg = nextMidi;
hasMidiMessage = iter->getNextEvent(nextMidi, midiEventPos);
return true;
}
return false;
}

void ObxdAudioProcessor::processBlock (AudioSampleBuffer& buffer, MidiBuffer& midiMessages)
{
//SSE flags set
//_MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON);
//_MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_ON);
MidiBuffer::Iterator ppp(midiMessages);
const ScopedLock sl (this->getCallbackLock());
hasMidiMessage = ppp.getNextEvent(*nextMidi,midiEventPos);
hasMidiMessage = ppp.getNextEvent(nextMidi,midiEventPos);

int samplePos = 0;
int numSamples = buffer.getNumSamples();
float* channelData1 = buffer.getWritePointer(0);
float* channelData2 = buffer.getWritePointer(1);

AudioPlayHead::CurrentPositionInfo pos;
if (getPlayHead() != 0 && getPlayHead()->getCurrentPosition (pos))
{
synth.setPlayHead(pos.bpm,pos.ppqPosition);
}

while (samplePos < numSamples)
{
processMidiPerSample(&ppp,samplePos);

synth->processSample(channelData1+samplePos,channelData2+samplePos);
synth.processSample(channelData1+samplePos,channelData2+samplePos);

samplePos++;
}
}

//==============================================================================
#if ! JUCE_AUDIOPROCESSOR_NO_GUI
bool ObxdAudioProcessor::hasEditor() const
{
return true; // (change this to false if you choose to not supply an editor)
return true;
}

AudioProcessorEditor* ObxdAudioProcessor::createEditor()
{
return new ObxdAudioProcessorEditor (this);
//return NULL;
return new ObxdAudioProcessorEditor (this);
}
#endif

//==============================================================================
void ObxdAudioProcessor::getStateInformation (MemoryBlock& destData)
{
//XmlElement* const xmlState = getXmlFromBinary(;
// 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.
XmlElement xmlState = XmlElement("Datsounds");
xmlState.setAttribute(S("currentProgram"),programs.currentProgram);
XmlElement* xprogs= new XmlElement("programs");
for(int i = 0 ; i < PROGRAMCOUNT;i++)
{
XmlElement* xpr = new XmlElement("program");
xpr->setAttribute(S("programName"),programs.programs[i].name);
for(int k = 0 ; k < PARAM_COUNT;k++)
{
xpr->setAttribute(String(k), programs.programs[i].values[k]);
}
xprogs->addChildElement(xpr);
}
xmlState.addChildElement(xprogs);
copyXmlToBinary(xmlState,destData);
xmlState.setAttribute(S("currentProgram"), programs.currentProgram);

XmlElement* xprogs = new XmlElement("programs");
for (int i = 0; i < PROGRAMCOUNT; ++i)
{
XmlElement* xpr = new XmlElement("program");
xpr->setAttribute(S("programName"), programs.programs[i].name);

for (int k = 0; k < PARAM_COUNT; ++k)
{
xpr->setAttribute(String(k), programs.programs[i].values[k]);
}

xprogs->addChildElement(xpr);
}

xmlState.addChildElement(xprogs);

copyXmlToBinary(xmlState,destData);
}

void ObxdAudioProcessor::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.
XmlElement* const xmlState = getXmlFromBinary(data,sizeInBytes);
XmlElement* xprogs = xmlState->getFirstChildElement();
if(xprogs->hasTagName(S("programs")));
if (XmlElement* const xmlState = getXmlFromBinary(data,sizeInBytes))
{
int i = 0 ;
forEachXmlChildElement (*xprogs, e)
{
XmlElement* xprogs = xmlState->getFirstChildElement();
if (xprogs->hasTagName(S("programs")))
{
int i = 0;
forEachXmlChildElement(*xprogs, e)
{
programs.programs[i].setDefaultValues();
for(int k = 0 ; k < PARAM_COUNT;k++)

for (int k = 0; k < PARAM_COUNT; ++k)
{
programs.programs[i].values[k] = e->getDoubleAttribute(String(k),programs.programs[i].values[k]);
programs.programs[i].values[k] = e->getDoubleAttribute(String(k), programs.programs[i].values[k]);
}
programs.programs[i].name= e->getStringAttribute(S("programName"),S("Default"));
i++;
}

programs.programs[i].name = e->getStringAttribute(S("programName"), S("Default"));

++i;
}
}

setCurrentProgram(xmlState->getIntAttribute(S("currentProgram"), 0));

delete xmlState;
}
setCurrentProgram(xmlState->getIntAttribute(S("currentProgram"),0));
delete xmlState;
}

void ObxdAudioProcessor::setCurrentProgramStateInformation(const void* data,int sizeInBytes)
{
XmlElement* const e = getXmlFromBinary(data,sizeInBytes);
programs.currentProgramPtr->setDefaultValues();
for(int k = 0 ; k < PARAM_COUNT;k++)
{
programs.currentProgramPtr->values[k] = e->getDoubleAttribute(String(k),programs.currentProgramPtr->values[k]);
}
programs.currentProgramPtr->name = e->getStringAttribute(S("programName"),S("Default"));
setCurrentProgram(programs.currentProgram);
if (XmlElement* const e = getXmlFromBinary(data, sizeInBytes))
{
programs.currentProgramPtr->setDefaultValues();

for (int k = 0; k < PARAM_COUNT; ++k)
{
programs.currentProgramPtr->values[k] = e->getDoubleAttribute(String(k), programs.currentProgramPtr->values[k]);
}

programs.currentProgramPtr->name = e->getStringAttribute(S("programName"), S("Default"));

setCurrentProgram(programs.currentProgram);

delete e;
}
}

void ObxdAudioProcessor::getCurrentProgramStateInformation(MemoryBlock& destData)
{
XmlElement xmlState = XmlElement("Datsounds");
for(int k = 0 ; k < PARAM_COUNT;k++)

for (int k = 0; k < PARAM_COUNT; ++k)
{
xmlState.setAttribute(String(k), programs.currentProgramPtr->values[k]);
}

xmlState.setAttribute(S("programName"), programs.currentProgramPtr->name);

copyXmlToBinary(xmlState, destData);
}

//==============================================================================
bool ObxdAudioProcessor::loadFromFXBFile(const File& fxbFile)
{
MemoryBlock mb;
if (! fxbFile.loadFileAsData(mb))
return false;

const void* const data = mb.getData();
const size_t dataSize = mb.getSize();

if (dataSize < 28)
return false;

const fxSet* const set = (const fxSet*) data;

if ((! compareMagic (set->chunkMagic, "CcnK")) || fxbSwap (set->version) > fxbVersionNum)
return false;

if (compareMagic (set->fxMagic, "FxBk"))
{
// bank of programs
if (fxbSwap (set->numPrograms) >= 0)
{
const int oldProg = getCurrentProgram();
const int numParams = fxbSwap (((const fxProgram*) (set->programs))->numParams);
const int progLen = (int) sizeof (fxProgram) + (numParams - 1) * (int) sizeof (float);

for (int i = 0; i < fxbSwap (set->numPrograms); ++i)
{
if (i != oldProg)
{
xmlState.setAttribute(String(k), programs.currentProgramPtr->values[k]);
const fxProgram* const prog = (const fxProgram*) (((const char*) (set->programs)) + i * progLen);
if (((const char*) prog) - ((const char*) set) >= (ssize_t) dataSize)
return false;

if (fxbSwap (set->numPrograms) > 0)
setCurrentProgram (i);

if (! restoreProgramSettings (prog))
return false;
}
}

if (fxbSwap (set->numPrograms) > 0)
setCurrentProgram (oldProg);

const fxProgram* const prog = (const fxProgram*) (((const char*) (set->programs)) + oldProg * progLen);
if (((const char*) prog) - ((const char*) set) >= (ssize_t) dataSize)
return false;

if (! restoreProgramSettings (prog))
return false;
}
}
xmlState.setAttribute(S("programName"),programs.currentProgramPtr->name);
copyXmlToBinary(xmlState,destData);
else if (compareMagic (set->fxMagic, "FxCk"))
{
// single program
const fxProgram* const prog = (const fxProgram*) data;

if (! compareMagic (prog->chunkMagic, "CcnK"))
return false;

changeProgramName (getCurrentProgram(), prog->prgName);

for (int i = 0; i < fxbSwap (prog->numParams); ++i)
setParameter (i, fxbSwapFloat (prog->params[i]));
}
else if (compareMagic (set->fxMagic, "FBCh"))
{
// non-preset chunk
const fxChunkSet* const cset = (const fxChunkSet*) data;

if ((size_t) fxbSwap (cset->chunkSize) + sizeof (fxChunkSet) - 8 > (size_t) dataSize)
return false;

setStateInformation(cset->chunk, fxbSwap (cset->chunkSize));
}
else if (compareMagic (set->fxMagic, "FPCh"))
{
// preset chunk
const fxProgramSet* const cset = (const fxProgramSet*) data;

if ((size_t) fxbSwap (cset->chunkSize) + sizeof (fxProgramSet) - 8 > (size_t) dataSize)
return false;

setCurrentProgramStateInformation(cset->chunk, fxbSwap (cset->chunkSize));

changeProgramName (getCurrentProgram(), cset->name);
}
else
{
return false;
}

currentBank = fxbFile.getFileName();

updateHostDisplay();

return true;
}

bool ObxdAudioProcessor::restoreProgramSettings(const fxProgram* const prog)
{
if (compareMagic (prog->chunkMagic, "CcnK")
&& compareMagic (prog->fxMagic, "FxCk"))
{
changeProgramName (getCurrentProgram(), prog->prgName);

for (int i = 0; i < fxbSwap (prog->numParams); ++i)
setParameter (i, fxbSwapFloat (prog->params[i]));

return true;
}

return false;
}

//==============================================================================
void ObxdAudioProcessor::scanAndUpdateBanks()
{
bankFiles.clearQuick();

DirectoryIterator it(getBanksFolder(), false, "*.fxb", File::findFiles);
while (it.next())
{
bankFiles.add(it.getFile());
}
}

const Array<File>& ObxdAudioProcessor::getBankFiles() const
{
return bankFiles;
}

File ObxdAudioProcessor::getCurrentBankFile() const
{
return getBanksFolder().getChildFile(currentBank);
}

//==============================================================================
File ObxdAudioProcessor::getDocumentFolder() const
{
File folder = File::getSpecialLocation(File::userDocumentsDirectory).getChildFile("discoDSP").getChildFile("OB-Xd");
if (folder.isSymbolicLink())
folder = folder.getLinkedTarget();
return folder;
}

File ObxdAudioProcessor::getSkinFolder() const
{
return getDocumentFolder().getChildFile("Skins");
}

File ObxdAudioProcessor::getBanksFolder() const
{
return getDocumentFolder().getChildFile("Banks");
}

File ObxdAudioProcessor::getCurrentSkinFolder() const
{
return getSkinFolder().getChildFile(currentSkin);
}

void ObxdAudioProcessor::setCurrentSkinFolder(const String& folderName)
{
currentSkin = folderName;

config->setValue("skin", folderName);
config->setNeedsToBeSaved(true);
}

//==============================================================================
// This creates new instances of the plugin..
AudioProcessor* JUCE_CALLTYPE createPluginFilter()


+ 147
- 33
ports/obxd/source/PluginProcessor.h View File

@@ -1,26 +1,122 @@
/*
==============================================================================
==============================================================================
This file is part of Obxd synthesizer.

This file was auto-generated!
Copyright © 2013-2014 Filatov Vadim
Contact author via email :
justdat_@_e1.ru

It contains the basic startup code for a Juce application.
This file may be licensed under the terms of of the
GNU General Public License Version 2 (the ``GPL'').

==============================================================================
*/
Software distributed under the License is distributed
on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either
express or implied. See the GPL for the specific language
governing rights and limitations.

You should have received a copy of the GPL along with this
program. If not, go to http://www.gnu.org/licenses/gpl.html
or write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
==============================================================================
*/

#ifndef PLUGINPROCESSOR_H_INCLUDED
#define PLUGINPROCESSOR_H_INCLUDED

#include "JuceHeader.h"
#include "Engine/SynthEngine.h"
#include <stack>
//#include <stack>
#include "Engine/midiMap.h"
#include "Engine/ObxdBank.h"

//==============================================================================
const int fxbVersionNum = 1;

struct fxProgram
{
int32 chunkMagic; // 'CcnK'
int32 byteSize; // of this chunk, excl. magic + byteSize
int32 fxMagic; // 'FxCk'
int32 version;
int32 fxID; // fx unique id
int32 fxVersion;
int32 numParams;
char prgName[28];
float params[1]; // variable no. of parameters
};

struct fxSet
{
int32 chunkMagic; // 'CcnK'
int32 byteSize; // of this chunk, excl. magic + byteSize
int32 fxMagic; // 'FxBk'
int32 version;
int32 fxID; // fx unique id
int32 fxVersion;
int32 numPrograms;
char future[128];
fxProgram programs[1]; // variable no. of programs
};

struct fxChunkSet
{
int32 chunkMagic; // 'CcnK'
int32 byteSize; // of this chunk, excl. magic + byteSize
int32 fxMagic; // 'FxCh', 'FPCh', or 'FBCh'
int32 version;
int32 fxID; // fx unique id
int32 fxVersion;
int32 numPrograms;
char future[128];
int32 chunkSize;
char chunk[8]; // variable
};

struct fxProgramSet
{
int32 chunkMagic; // 'CcnK'
int32 byteSize; // of this chunk, excl. magic + byteSize
int32 fxMagic; // 'FxCh', 'FPCh', or 'FBCh'
int32 version;
int32 fxID; // fx unique id
int32 fxVersion;
int32 numPrograms;
char name[28];
int32 chunkSize;
char chunk[8]; // variable
};

// Compares a magic value in either endianness.
static inline bool compareMagic (int32 magic, const char* name) noexcept
{
return magic == (int32) ByteOrder::littleEndianInt (name)
|| magic == (int32) ByteOrder::bigEndianInt (name);
}

static inline int32 fxbName (const char* name) noexcept { return (int32) ByteOrder::littleEndianInt (name); }
static inline int32 fxbSwap (const int32 x) noexcept { return (int32) ByteOrder::swapIfLittleEndian ((uint32) x); }

static inline float fxbSwapFloat (const float x) noexcept
{
#ifdef JUCE_LITTLE_ENDIAN
union { uint32 asInt; float asFloat; } n;
n.asFloat = x;
n.asInt = ByteOrder::swap (n.asInt);
return n.asFloat;
#else
return x;
#endif
}

//==============================================================================
/**
*/
class ObxdAudioProcessor : public AudioProcessor, //public AudioProcessorListener,
public ChangeBroadcaster
class ObxdAudioProcessor :
public AudioProcessor,
// public AudioProcessorListener,
public ChangeBroadcaster
{
public:
//==============================================================================
@@ -34,36 +130,17 @@ public:
void processBlock (AudioSampleBuffer& buffer, MidiBuffer& midiMessages);

//==============================================================================
#if ! JUCE_AUDIOPROCESSOR_NO_GUI
AudioProcessorEditor* createEditor();
bool hasEditor() const;
#endif

int lastMovedController,lastUsedParameter;

Random rnd;

MidiMessage* nextMidi,*midiMsg;
bool hasMidiMessage;
int midiEventPos;
//==============================================================================
void processMidiPerSample(MidiBuffer::Iterator* iter,const int samplePos);
bool getNextEvent(MidiBuffer::Iterator* iter,const int samplePos);

//==============================================================================
SynthEngine* synth;
//==============================================
ObxdBank programs;
//==============================================
const String getName() const;

int getNumParameters();

//


//==============================================================================
void initAllParams();
//

int getNumParameters();

float getParameter (int index);
void setParameter (int index, float newValue);
@@ -80,6 +157,7 @@ public:
bool producesMidi() const;
bool silenceInProducesSilenceOut() const;
double getTailLengthSeconds() const;
const String getName() const;

//==============================================================================
int getNumPrograms();
@@ -94,9 +172,45 @@ public:
void setCurrentProgramStateInformation(const void* data,int sizeInBytes);
void getCurrentProgramStateInformation(MemoryBlock& destData);

//==============================================================================
void scanAndUpdateBanks();
const Array<File>& getBankFiles() const;
bool loadFromFXBFile(const File& fxbFile);
bool restoreProgramSettings(const fxProgram* const prog);
File getCurrentBankFile() const;

//==============================================================================
const ObxdBank& getPrograms() const { return programs; }

//==============================================================================
File getDocumentFolder() const;
File getSkinFolder() const;
File getBanksFolder() const;

File getCurrentSkinFolder() const;
void setCurrentSkinFolder(const String& folderName);

private:
//==============================================================================
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ObxdAudioProcessor)
//==============================================================================
bool isHostAutomatedChange;

MidiMessage nextMidi, midiMsg;

bool hasMidiMessage;
int midiEventPos;

SynthEngine synth;
ObxdBank programs;

String currentSkin;
String currentBank;
Array<File> bankFiles;

ScopedPointer<PropertiesFile> config;
InterProcessLock configLock;

//==============================================================================
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ObxdAudioProcessor)
};

#endif // PLUGINPROCESSOR_H_INCLUDED

Loading…
Cancel
Save