Browse Source

Update obxd (discoDSP version)

tags/2018-04-16
falkTX 6 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;