@@ -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; | |||
} | |||
}; | |||
}; |
@@ -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; | |||
@@ -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,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)]; | |||
} | |||
}; | |||
}; |
@@ -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; | |||
} | |||
}; | |||
}; |
@@ -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; | |||
} | |||
}; |
@@ -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; | |||
} | |||
}; | |||
}; |
@@ -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; | |||
} | |||
}; | |||
}; |
@@ -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: | |||
} | |||
} | |||
}; | |||
}; |
@@ -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; | |||
} | |||
}; | |||
}; |
@@ -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) | |||
}; |
@@ -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, | |||
}; | |||
}; |
@@ -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]; | |||
} | |||
}; | |||
}; |
@@ -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]; | |||
} | |||
}; | |||
}; |
@@ -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)); | |||
} | |||
}; | |||
}; |
@@ -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]; | |||
} | |||
}; | |||
}; |
@@ -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 +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 |
@@ -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: | |||
} | |||
}; | |||
}; |
@@ -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 |
@@ -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 | |||
@@ -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()); | |||
} | |||
} |
@@ -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 |
@@ -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() | |||
@@ -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 |