diff --git a/Builds/MacOSX/Dexed.xcodeproj/project.xcworkspace/xcuserdata/asb2m10.xcuserdatad/UserInterfaceState.xcuserstate b/Builds/MacOSX/Dexed.xcodeproj/project.xcworkspace/xcuserdata/asb2m10.xcuserdatad/UserInterfaceState.xcuserstate
index 3e1947e..4253be1 100644
Binary files a/Builds/MacOSX/Dexed.xcodeproj/project.xcworkspace/xcuserdata/asb2m10.xcuserdatad/UserInterfaceState.xcuserstate and b/Builds/MacOSX/Dexed.xcodeproj/project.xcworkspace/xcuserdata/asb2m10.xcuserdatad/UserInterfaceState.xcuserstate differ
diff --git a/README.md b/README.md
index 8fd81d3..2428309 100644
--- a/README.md
+++ b/README.md
@@ -28,6 +28,7 @@ Changelog
* Modulation wheel support
* Now using the [Obxd](https://obxd.wordpress.com) 4-pole lowpass filter implementation
* Pitchbend range / step
+* Output VU status
Binary downloads
----------------
diff --git a/Source/DXComponents.cpp b/Source/DXComponents.cpp
index 7602b35..e0676de 100644
--- a/Source/DXComponents.cpp
+++ b/Source/DXComponents.cpp
@@ -413,6 +413,10 @@ void PitchEnvDisplay::paint(Graphics &g) {
}
}
+VuMeter::VuMeter() {
+ totalBlocks = 16;
+}
+
void VuMeter::paint(Graphics &g) {
// taken from the drawLevelMeter ;
float width = getWidth();
@@ -420,22 +424,16 @@ void VuMeter::paint(Graphics &g) {
g.setColour (Colours::black);
g.fillRoundedRectangle (0.0f, 0.0f, (float) width, (float) height, 0);
- /*g.setColour (Colours::black.withAlpha (0.2f));
- g.drawRoundedRectangle (1.0f, 1.0f, width - 2.0f, height - 2.0f, 3.0f, 1.0f);*/
-
- const int totalBlocks = 16;
+
const int numBlocks = roundToInt (totalBlocks * v);
const float h = (height - 6.0f) / (float) totalBlocks;
for (int i = 0; i < totalBlocks; ++i) {
- g.setColour (Colours::red);
if (i >= numBlocks)
g.setColour (Colours::red.withAlpha (0.2f));
else
g.setColour (Colours::red);
- //g.fillRoundedRectangle (3.0f + i * w + w * 0.1f, 3.0f, w * 0.8f, height - 6.0f, w * 0.4f);
-
- g.fillRoundedRectangle (3.0f, (height-3.0f) - (3.0f + i * h + h * 0.1f) , width - 6.0f, h * 0.8f, 0);
+ g.fillRoundedRectangle (3.0f, (height-4.0f) - (3.0f + i * h + h * 0.1f) , width - 6.0f, h * 0.8f, 0);
}
}
diff --git a/Source/DXComponents.h b/Source/DXComponents.h
index eda1895..63d29a2 100644
--- a/Source/DXComponents.h
+++ b/Source/DXComponents.h
@@ -50,8 +50,10 @@ public:
class VuMeter: public Component {
void paint(Graphics &g);
- public :
+public :
+ VuMeter();
float v;
+ int totalBlocks;
};
class LcdDisplay : public Component {
diff --git a/Source/GlobalEditor.cpp b/Source/GlobalEditor.cpp
index 50cea36..65ac533 100644
--- a/Source/GlobalEditor.cpp
+++ b/Source/GlobalEditor.cpp
@@ -165,6 +165,15 @@ GlobalEditor::GlobalEditor ()
addAndMakeVisible (lcdDisplay = new LcdDisplay());
lcdDisplay->setName ("lcdDisplay");
+ addAndMakeVisible (output = new Slider ("cutoff"));
+ output->setRange (0, 1, 0);
+ output->setSliderStyle (Slider::Rotary);
+ output->setTextBoxStyle (Slider::NoTextBox, false, 80, 20);
+ output->addListener (this);
+
+ addAndMakeVisible (vuOutput = new VuMeter());
+ vuOutput->setName ("vuOutput");
+
//[UserPreSize]
//[/UserPreSize]
@@ -174,6 +183,7 @@ GlobalEditor::GlobalEditor ()
//[Constructor] You can add your own custom stuff here..
lcdDisplay->systemMsg << "*** DEXED FM synthesizer ***";
+ vuOutput->totalBlocks = 6;
//[/Constructor]
}
@@ -207,6 +217,8 @@ GlobalEditor::~GlobalEditor()
feedback = nullptr;
algo = nullptr;
lcdDisplay = nullptr;
+ output = nullptr;
+ vuOutput = nullptr;
//[Destructor]. You can add your own custom destruction code here..
@@ -219,6 +231,24 @@ void GlobalEditor::paint (Graphics& g)
//[UserPrePaint] Add your own custom painting code here..
//[/UserPrePaint]
+ g.setColour (Colours::black);
+ g.setFont (Font (10.00f, Font::plain));
+ g.drawText (TRANS("Volume"),
+ 27, 73, 45, 15,
+ Justification::centred, true);
+
+ g.setColour (Colours::black);
+ g.setFont (Font (10.00f, Font::plain));
+ g.drawText (TRANS("Cutoff"),
+ 75, 73, 45, 15,
+ Justification::centred, true);
+
+ g.setColour (Colours::black);
+ g.setFont (Font (10.00f, Font::plain));
+ g.drawText (TRANS("Resonance"),
+ 123, 73, 45, 15,
+ Justification::centred, true);
+
//[UserPaint] Add your own custom painting code here..
//[/UserPaint]
@@ -231,8 +261,8 @@ void GlobalEditor::resized()
lfoAmDepth->setBounds (672, 64, 24, 24);
lfoPitchDepth->setBounds (648, 64, 24, 24);
lfoDelay->setBounds (624, 64, 24, 24);
- cutoff->setBounds (8, 40, 48, 48);
- reso->setBounds (64, 40, 48, 48);
+ cutoff->setBounds (80, 40, 40, 40);
+ reso->setBounds (128, 40, 40, 40);
pitchRate2->setBounds (752, 64, 32, 24);
pitchRate3->setBounds (776, 64, 32, 24);
pitchRate4->setBounds (800, 64, 32, 24);
@@ -249,7 +279,9 @@ void GlobalEditor::resized()
algoDisplay->setBounds (442, 8, 152, 74);
feedback->setBounds (568, 32, 24, 24);
algo->setBounds (568, 8, 24, 24);
- lcdDisplay->setBounds (8, 0, 256, 32);
+ lcdDisplay->setBounds (8, 0, 232, 32);
+ output->setBounds (32, 40, 40, 40);
+ vuOutput->setBounds (8, 44, 16, 38);
//[UserResized] Add your own custom resize handling here..
//[/UserResized]
}
@@ -372,6 +404,11 @@ void GlobalEditor::sliderValueChanged (Slider* sliderThatWasMoved)
//[UserSliderCode_algo] -- add your slider handling code here..
//[/UserSliderCode_algo]
}
+ else if (sliderThatWasMoved == output)
+ {
+ //[UserSliderCode_output] -- add your slider handling code here..
+ //[/UserSliderCode_output]
+ }
//[UsersliderValueChanged_Post]
//[/UsersliderValueChanged_Post]
@@ -403,6 +440,7 @@ void GlobalEditor::bind(DexedAudioProcessor *parent) {
parent->pitchEgRate[3]->bind(pitchRate4);
parent->fxCutoff->bind(cutoff);
parent->fxReso->bind(reso);
+ parent->output->bind(output);
algoDisplay->algo = &(parent->data[134]);
pitchEnvDisplay->pvalues = &(parent->data[126]);
processor = parent;
@@ -429,6 +467,11 @@ void GlobalEditor::updatePitchPos(int pos) {
pitchEnvDisplay->vPos = pos;
pitchEnvDisplay->repaint();
}
+
+void GlobalEditor::updateVu(float f) {
+ vuOutput->v = f;
+ vuOutput->repaint();
+}
//[/MiscUserCode]
@@ -445,7 +488,14 @@ BEGIN_JUCER_METADATA
parentClasses="public Component" constructorParams="" variableInitialisers=""
snapPixels="8" snapActive="1" snapShown="1" overlayOpacity="0.330"
fixedSize="1" initialWidth="855" initialHeight="90">
-
+
+
+
+
+
+
+
END_JUCER_METADATA
diff --git a/Source/GlobalEditor.h b/Source/GlobalEditor.h
index 597dd54..101f824 100644
--- a/Source/GlobalEditor.h
+++ b/Source/GlobalEditor.h
@@ -51,6 +51,7 @@ public:
void setSystemMessage(String msg);
void setParamMessage(String msg);
void updatePitchPos(int pos);
+ void updateVu(float v);
void updateDisplay();
//[/UserMethods]
@@ -92,6 +93,8 @@ private:
ScopedPointer feedback;
ScopedPointer algo;
ScopedPointer lcdDisplay;
+ ScopedPointer output;
+ ScopedPointer vuOutput;
//==============================================================================
diff --git a/Source/PluginData.cpp b/Source/PluginData.cpp
index 841df50..023e7f6 100644
--- a/Source/PluginData.cpp
+++ b/Source/PluginData.cpp
@@ -230,6 +230,7 @@ void DexedAudioProcessor::getStateInformation(MemoryBlock& destData) {
dexedState.setAttribute("cutoff", fx.uiCutoff);
dexedState.setAttribute("reso", fx.uiReso);
+ dexedState.setAttribute("gain", fx.uiGain);
dexedState.setAttribute("currentProgram", currentProgram);
char sysex_blob[4104];
@@ -257,6 +258,7 @@ void DexedAudioProcessor::setStateInformation(const void* source, int sizeInByte
fx.uiCutoff = root->getDoubleAttribute("cutoff");
fx.uiReso = root->getDoubleAttribute("reso");
+ fx.uiGain = root->getDoubleAttribute("gain");
currentProgram = root->getIntAttribute("currentProgram");
XmlElement *dexedBlob = root->getChildByName("dexedBlob");
diff --git a/Source/PluginEditor.cpp b/Source/PluginEditor.cpp
index 84fa972..7292760 100644
--- a/Source/PluginEditor.cpp
+++ b/Source/PluginEditor.cpp
@@ -278,6 +278,7 @@ void DexedAudioProcessorEditor::timerCallback() {
operators[i].updateEnvPos(processor->voiceStatus.ampStep[5 - i]);
}
global.updatePitchPos(processor->voiceStatus.pitchStep);
+ global.updateVu(processor->vuSignal);
}
void DexedAudioProcessorEditor::updateUI() {
diff --git a/Source/PluginFx.cpp b/Source/PluginFx.cpp
index 4e6180f..149fe7c 100644
--- a/Source/PluginFx.cpp
+++ b/Source/PluginFx.cpp
@@ -75,9 +75,11 @@ void PluginFx::init(int sr) {
uiCutoff = 1;
uiReso = 0;
+ uiGain = 0.8;
pCutoff = -1;
pReso = -1;
+ pGain = -1;
}
inline float PluginFx::NR24(float sample,float g,float lpc) {
@@ -95,66 +97,73 @@ inline float PluginFx::NR(float sample, float g) {
void PluginFx::process(float *work, int sampleSize) {
// don't apply the LPF if the cutoff is to maximum
- if ( uiCutoff == 1 )
- return;
-
- if ( uiCutoff != pCutoff || uiReso != pReso ) {
- rReso = (0.991-logsc(1-uiReso,0,0.991,40));
- R24 = 3.5 * rReso;
+ if ( uiCutoff != 1 ) {
+ if ( uiCutoff != pCutoff || uiReso != pReso ) {
+ rReso = (0.991-logsc(1-uiReso,0,0.991));
+ R24 = 3.5 * rReso;
- float cutoffNorm = logsc(uiCutoff,60,19000,30);
- rCutoff = (float)tan(cutoffNorm * sampleRateInv * juce::float_Pi);
+ float cutoffNorm = logsc(uiCutoff,60,19000);
+ rCutoff = (float)tan(cutoffNorm * sampleRateInv * juce::float_Pi);
+
+ pCutoff = uiCutoff;
+ pReso = uiReso;
+
+ R = 1 - rReso;
+ }
- pCutoff = uiCutoff;
- pReso = uiReso;
-
- R = 1 - rReso;
- }
-
- // THIS IS MY FAVORITE 4POLE OBXd filter
-
- // maybe smooth this value
- float g = rCutoff;
- float lpc = g / (1 + g);
-
- for(int i=0; i < sampleSize; i++ ) {
- float s = work[i];
- s = s - 0.45*tptlpupw(c,s,15,sampleRateInv);
- s = tptpc(d,s,bright);
+ // THIS IS MY FAVORITE 4POLE OBXd filter
- float y0 = NR24(s,g,lpc);
+ // maybe smooth this value
+ float g = rCutoff;
+ float lpc = g / (1 + g);
- //first low pass in cascade
- double v = (y0 - s1) * lpc;
- double res = v + s1;
- s1 = res + v;
+ for(int i=0; i < sampleSize; i++ ) {
+ float s = work[i];
+ s = s - 0.45*tptlpupw(c,s,15,sampleRateInv);
+ s = tptpc(d,s,bright);
+
+ float y0 = NR24(s,g,lpc);
+
+ //first low pass in cascade
+ double v = (y0 - s1) * lpc;
+ double res = v + s1;
+ s1 = res + v;
+
+ //damping
+ s1 =atan(s1*rcor24)*rcor24Inv;
+ float y1= res;
+ float y2 = tptpc(s2,y1,g);
+ float y3 = tptpc(s3,y2,g);
+ float y4 = tptpc(s4,y3,g);
+ float mc;
- //damping
- s1 =atan(s1*rcor24)*rcor24Inv;
- float y1= res;
- float y2 = tptpc(s2,y1,g);
- float y3 = tptpc(s3,y2,g);
- float y4 = tptpc(s4,y3,g);
- float mc;
+ switch(mmch) {
+ case 0:
+ mc = ((1 - mmt) * y4 + (mmt) * y3);
+ break;
+ case 1:
+ mc = ((1 - mmt) * y3 + (mmt) * y2);
+ break;
+ case 2:
+ mc = ((1 - mmt) * y2 + (mmt) * y1);
+ break;
+ case 3:
+ mc = y1;
+ break;
+ }
- switch(mmch) {
- case 0:
- mc = ((1 - mmt) * y4 + (mmt) * y3);
- break;
- case 1:
- mc = ((1 - mmt) * y3 + (mmt) * y2);
- break;
- case 2:
- mc = ((1 - mmt) * y2 + (mmt) * y1);
- break;
- case 3:
- mc = y1;
- break;
+ //half volume comp
+ work[i] = mc * (1 + R24 * 0.45);
}
-
- //half volume comp
- work[i] = mc * (1 + R24 * 0.45);
}
+
+ if ( uiGain != pGain ) {
+ rGain = linsc(uiGain, 0, 1.25);
+ pGain = uiGain;
+ }
+
+ for(int i=0; i < sampleSize; i++ )
+ work[i] *= rGain;
}
/*
diff --git a/Source/PluginFx.h b/Source/PluginFx.h
index b100601..6f02ca4 100644
--- a/Source/PluginFx.h
+++ b/Source/PluginFx.h
@@ -39,11 +39,13 @@ class PluginFx {
// preprocess values taken the UI
float rCutoff;
float rReso;
+ float rGain;
// thread values; if these are different from the UI,
// it needs to be recalculated.
float pReso;
float pCutoff;
+ float pGain;
// I am still keeping the 2pole w/multimode filter
inline float NR(float sample, float g);
@@ -56,6 +58,7 @@ public:
// this is set directly by the ui / parameter
float uiCutoff;
float uiReso;
+ float uiGain;
void init(int sampleRate);
void process(float *work, int sampleSize);
diff --git a/Source/PluginParam.cpp b/Source/PluginParam.cpp
index 74d6476..b777afa 100644
--- a/Source/PluginParam.cpp
+++ b/Source/PluginParam.cpp
@@ -215,6 +215,9 @@ void DexedAudioProcessor::initCtrl() {
fxReso = new CtrlFloat("Resonance", &fx.uiReso);
ctrl.add(fxReso);
+ output = new CtrlFloat("Output", &fx.uiGain);
+ ctrl.add(output);
+
algo = new CtrlDX("ALGORITHM", 32, 134, 1);
ctrl.add(algo);
diff --git a/Source/PluginProcessor.cpp b/Source/PluginProcessor.cpp
index eb6fbdb..d8f6968 100644
--- a/Source/PluginProcessor.cpp
+++ b/Source/PluginProcessor.cpp
@@ -47,6 +47,7 @@ DexedAudioProcessor::DexedAudioProcessor() {
currentNote = -1;
workBlock = NULL;
+ vuSignal = 0;
initCtrl();
setCurrentProgram(0);
sendSysexChange = true;
@@ -175,14 +176,24 @@ void DexedAudioProcessor::processBlock(AudioSampleBuffer& buffer, MidiBuffer& mi
*/
processSamples(block, workBlock);
- for(int i = 0; i < block; i++ ) {
+ for(int i = 0; i < block; i++ )
channelData[i+samplePos] = workBlock[i];
- }
samplePos += block;
}
fx.process(channelData, numSamples);
+ for(int i=0; i vuSignal)
+ vuSignal = s;
+ else if (vuSignal > 0.001f)
+ vuSignal *= decayFactor;
+ else
+ vuSignal = 0;
+ }
// DX7 is a mono synth
for (int channel = 1; channel < getNumInputChannels(); ++channel) {
diff --git a/Source/PluginProcessor.h b/Source/PluginProcessor.h
index 911c708..f26e7ef 100644
--- a/Source/PluginProcessor.h
+++ b/Source/PluginProcessor.h
@@ -114,6 +114,8 @@ public :
bool forceRefreshUI;
+ float vuSignal;
+
Array ctrl;
OperatorCtrl opCtrl[6];
@@ -133,6 +135,7 @@ public :
ScopedPointer fxCutoff;
ScopedPointer fxReso;
+ ScopedPointer output;
int importSysex(const char *imported);
void setDxValue(int offset, int v);