Bass Pedal - Plugin version

Demo:

Design

I designed the Bass Pedal plugin as a software plugin version of my hardware bass pedal. The plugin is tailored towards bass players who are mixing their own recordings and want a quick and easy way to get the "fat" or "punchy" sound they are looking for, even if they don't have a strong understanding of compression, EQ, and saturation.

I used the JUCE plugin framework for this project. I had already designed the DSP effect objects in C++, so all I really had to do was implement the effects in JUCE and design a GUI for it. As I discussed regarding the hardware bass pedal I designed, the "melody" mode is not designed to be used simultaneously with the other effects, so I had to create some logic to disable the other buttons while "melody" mode is on. They save the state of the other three settings, reloading them when the "melody" mode is turned off.

Code

Because I had already made all the C++ effect objects, the bulk of the design just involved creating the GUI. The GUI rendering code, event listeners, and the audio processing code are below. Click on one of the functions to view the code.

void BassPedalAudioProcessor::processBlock (juce::AudioBuffer& buffer, juce::MidiBuffer& midiMessages) { juce::ScopedNoDenormals noDenormals; auto totalNumInputChannels = getTotalNumInputChannels(); auto totalNumOutputChannels = getTotalNumOutputChannels(); for (auto i = totalNumInputChannels; i < totalNumOutputChannels; ++i) buffer.clear (i, 0, buffer.getNumSamples()); // UPDATE fx parameters FatPunchParameters fpParams = fatPunchL.getParameters(); fpParams.fatOn = fatOn; fpParams.darkenOn = darkOn; fpParams.punchCompOn = punchOn; fatPunchL.setParameters(fpParams); fatPunchR.setParameters(fpParams); MelodyModeParameters mmParams = mmL.getParameters(); mmParams.on = melodyOn; mmL.setParameters(mmParams); mmR.setParameters(mmParams); //update gain here float gainFactor = dB2Raw(inputGainVal); auto* channelDataL = buffer.getWritePointer(0); auto* channelDataR = buffer.getWritePointer(1); for (int i = 0; i < buffer.getNumSamples(); i++) { auto xnL = channelDataL[i]; auto xnR = channelDataR[i]; xnL *= gainFactor; xnR *= gainFactor; xnL = fatPunchL.processAudioSample(xnL); xnR = fatPunchR.processAudioSample(xnR); xnL = mmL.processAudioSample(xnL); xnR = mmR.processAudioSample(xnR); channelDataL[i] = xnL; channelDataR[i] = xnR; } }
fatBtn.onClick = [this] { if (!audioProcessor.melodyOn) audioProcessor.fatOn = !audioProcessor.fatOn; repaint(); }; punchBtn.onClick = [this] { if (!audioProcessor.melodyOn) audioProcessor.punchOn = !audioProcessor.punchOn; repaint(); }; darkBtn.onClick = [this] { if (!audioProcessor.melodyOn) audioProcessor.darkOn = !audioProcessor.darkOn; repaint(); }; melodyBtn.onClick = [this] { if (!audioProcessor.melodyOn) { //turn on audioProcessor.melodyOn = true; //save other modes to memory audioProcessor.fatOn_mem = audioProcessor.fatOn; audioProcessor.darkOn_mem = audioProcessor.darkOn; audioProcessor.punchOn_mem = audioProcessor.punchOn; //turn off other modes audioProcessor.fatOn = false; audioProcessor.darkOn = false; audioProcessor.punchOn = false; } else { //turn off audioProcessor.melodyOn = false; //recall other modes from memory audioProcessor.fatOn = audioProcessor.fatOn_mem; audioProcessor.punchOn = audioProcessor.punchOn_mem; audioProcessor.darkOn = audioProcessor.darkOn_mem; } repaint(); };
void BassPedalAudioProcessorEditor::paint (juce::Graphics& g) { // (Our component is opaque, so we must completely fill the background with a solid colour) g.fillAll (getLookAndFeel().findColour (juce::ResizableWindow::backgroundColourId)); //draw LEDs int ledWidth = 20; g.setColour(juce::Colour(0xffaa0000)); g.drawEllipse((gridX / 2) + gridX * 1 - ledWidth / 2, 50, ledWidth, ledWidth, 3); g.drawEllipse((gridX / 2) + gridX * 2 - ledWidth / 2, 50, ledWidth, ledWidth, 3); g.drawEllipse((gridX / 2) + gridX * 3 - ledWidth / 2, 50, ledWidth, ledWidth, 3); g.drawEllipse((gridX / 2) + gridX * 4 - ledWidth / 2, 50, ledWidth, ledWidth, 3); g.setColour(juce::Colour(0xffff0000)); int ledPad = 2; if (audioProcessor.fatOn) g.fillEllipse((gridX / 2) + gridX * 1 - ledWidth / 2 + ledPad, 50 + ledPad, ledWidth - 2 * ledPad, ledWidth - 2 * ledPad); if (audioProcessor.punchOn) g.fillEllipse((gridX / 2) + gridX * 2 - ledWidth / 2 + ledPad, 50 + ledPad, ledWidth - 2 * ledPad, ledWidth - 2 * ledPad); if (audioProcessor.darkOn) g.fillEllipse((gridX / 2) + gridX * 3 - ledWidth / 2 + ledPad, 50 + ledPad, ledWidth - 2 * ledPad, ledWidth - 2 * ledPad); if (audioProcessor.melodyOn) g.fillEllipse((gridX / 2) + gridX * 4 - ledWidth / 2 + ledPad, 50 + ledPad, ledWidth - 2 * ledPad, ledWidth - 2 * ledPad); }