From 3104d39f9f433ca8640b21414435f499a5930e49 Mon Sep 17 00:00:00 2001 From: asb2m10 Date: Sun, 16 Mar 2014 02:55:27 -0400 Subject: [PATCH] Output Gain --- .../UserInterfaceState.xcuserstate | Bin 100201 -> 101126 bytes README.md | 1 + Source/DXComponents.cpp | 14 +-- Source/DXComponents.h | 4 +- Source/GlobalEditor.cpp | 70 +++++++++-- Source/GlobalEditor.h | 3 + Source/PluginData.cpp | 2 + Source/PluginEditor.cpp | 1 + Source/PluginFx.cpp | 113 ++++++++++-------- Source/PluginFx.h | 3 + Source/PluginParam.cpp | 3 + Source/PluginProcessor.cpp | 15 ++- Source/PluginProcessor.h | 3 + 13 files changed, 162 insertions(+), 70 deletions(-) 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 3e1947e8bb594398ca64b5ddca34df26f8a0dd0c..4253be1498c0c08acc753159bcef0f91930ca407 100644 GIT binary patch delta 28345 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 delta 28158 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 Q3LXE?|NVcjp%PR7KP%%mFaQ7m 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);