quantumVERB  1.0.0
A FOSS convolution reverb plugin
PluginEditor.cpp
1 /*
2  ==============================================================================
3 
4  This file was auto-generated!
5 
6  It contains the basic framework code for a JUCE plugin editor.
7 
8  ==============================================================================
9 */
10 
11 #include "PluginEditor.h"
12 
13 #include "PluginProcessor.h"
14 
15 #include <string.h>
16 
17 namespace reverb
18 {
19 
20  //==============================================================================
21  /**
22  * @brief Constructs an AudioProcessorEditor object associated with an AudioProcessor
23  *
24  * Creates an AudioProcessorEditor and each of its components. Constructs the UI by adding
25  * all the required elements. It handles element placement, plugin window default size and
26  * how to handle the resizing of the window.
27  *
28  * @param [in] processor Pointer to main processor
29  *
30  */
32  : juce::AudioProcessorEditor(&p), processor(p), parameters(p.parameters),
34  lowShelfFilterBlock(p, 0, "low-shelf filter"), peakLowFilterBlock(p, 1, "low-peak filter"),
35  peakHighFilterBlock(p, 2, "high-peak filter"), highShelfFilterBlock(p, 3, "high-shelf filter"),
37  {
38  // Make sure that before the constructor has finished, you've set the
39  // editor's size to whatever you need it to be.
40  setResizable(true, true);
41  setResizeLimits(800, 640, 1920, 1080);
42 
43  // Look and feel
44  setLookAndFeel(&lookAndFeel);
45 
46  // Display header block
47  addAndMakeVisible(headerBlock);
48 
49  // Display graph block
50  addAndMakeVisible(graphBlock);
51 
52  // Display reverb params block
53  addAndMakeVisible(reverbBlock);
54 
55  // Build filter blocks
56  filterBlockNames = { "low-shelf", "peak (low)", "peak (high)", "high-shelf" };
57 
58  for (auto filterBlock : filterBlocks)
59  {
60  addAndMakeVisible(*filterBlock);
61  }
62 
63  // Set listeners for IR graph
64  headerBlock.irChoice.addListener(&graphBlock);
65  headerBlock.irChoice.addListener(this);
66 
67  reverbBlock.irLength.addListener(&graphBlock);
68  reverbBlock.preDelay.addListener(&graphBlock);
69  reverbBlock.irGain.addListener(&graphBlock);
70  reverbBlock.outGain.addListener(&graphBlock);
71  reverbBlock.wetRatio.addListener(&graphBlock);
72 
73  for (auto& filterBlock : filterBlocks)
74  {
75  filterBlock->freq.addListener(&graphBlock);
76  filterBlock->q.addListener(&graphBlock);
77  filterBlock->gain.addListener(&graphBlock);
78  }
79 
80  // Calls resized when creating UI to position all the elements as if window was resized.
81  this->resized();
82  }
83 
84  //==============================================================================
85  AudioProcessorEditor::~AudioProcessorEditor()
86  {
87  setLookAndFeel(nullptr);
88  }
89 
90  void AudioProcessorEditor::paint(juce::Graphics& g)
91  {
92  // (Our component is opaque, so we must completely fill the background with a solid colour)
93  g.fillAll(getLookAndFeel().findColour(juce::ResizableWindow::backgroundColourId));
94 
95  g.setColour(juce::Colours::white);
96  g.setFont(15.0f);
97  }
98 
99  //==============================================================================
100  /**
101  * @brief Manages the layout of AudioProcessorEditor when the window is resized
102  *
103  * This function defines all the relative positioning of the various UI elements.
104  */
106  {
107  juce::Rectangle<int> bounds(getLocalBounds());
108 
109  int width = bounds.getWidth();
110  int height = bounds.getHeight();
111 
112  int padding = (int)(PADDING_REL * height);
113 
114  // Header block
115  auto headerBounds = bounds;
116 
117  headerBounds.setBottom((int)(0.13 * height));
118 
119  headerBounds.reduce(padding, padding);
120 
121  headerBlock.setBounds(headerBounds);
122 
123  // Graph
124  auto graphBounds = bounds;
125 
126  graphBounds.setTop(headerBounds.getBottom());
127  graphBounds.setBottom(headerBounds.getBottom() + padding + (int)(0.52 * height));
128  graphBounds.setRight((int)(0.75 * width));
129 
130  graphBounds.reduce(padding, padding);
131 
132  graphBlock.setBounds(graphBounds);
133 
134  // Reverb block
135  auto reverbBounds = bounds;
136 
137  reverbBounds.setTop(headerBounds.getBottom());
138  reverbBounds.setBottom(headerBounds.getBottom() + padding + (int)std::round(0.52 * height));
139  reverbBounds.setLeft(graphBounds.getRight() + padding);
140 
141  reverbBounds.reduce(padding, padding);
142 
143  reverbBlock.setBounds(reverbBounds);
144 
145  // Filters
146  auto filterBounds = bounds;
147 
148  filterBounds.setTop(reverbBounds.getBottom());
149  filterBounds.setBottom(reverbBounds.getBottom() + padding + (int)std::round(0.35 * height));
150 
151  int filterBlockWidth = width / 4;
152 
153  for (int i = 0; i < 4; ++i)
154  {
155  auto thisFilterBounds = filterBounds.removeFromLeft(filterBlockWidth);
156  thisFilterBounds.reduce(padding, padding);
157 
158  filterBlocks[i]->setBounds(thisFilterBounds);
159  }
160  }
161 
162  /**
163  * @brief Callback function to open the popup menu asynchronously.
164  *
165  * @details This function will open a popup menu when the user clicks
166  * on the IR selection's button. The first item in the menu
167  * will let the user choose a custom IR from a file browser,
168  * while the other items will display the IRs from the IR bank.
169  * @param [in] clickedButton Pointer to the button clicked by the user.
170  */
171  void AudioProcessorEditor::buttonClicked(juce::Button* clickedButton)
172  {
173  if (clickedButton != nullptr && clickedButton == &headerBlock.irChoice) {
174  juce::PopupMenu m;
175  m.addItem(1, "Load custom IR...");
176  m.addSeparator();
177 
178  for (int i = 0; i < headerBlock.previousSelectedIRs.size(); i++)
179  {
180  m.addItem(i + 2, headerBlock.previousSelectedIRs[i]);
181  }
182 
183  m.addSeparator();
184 
185  for (auto irFile : IRBank::getInstance().buffers)
186  {
187  m.addItem(m.getNumItems() + 1, irFile.first);
188  }
189 
190  m.showMenuAsync(juce::PopupMenu::Options(),
191  juce::ModalCallbackFunction::forComponent(menuCallback, &headerBlock));
192  }
193  }
194 
195  /**
196  * @brief Callback function to open the popup menu asynchronously.
197  *
198  * @details This function will open a file browser if the user clicked on the first
199  * item in the dropdown menu. Any other item will load the appropriate IR
200  * from the IR bank.
201  * @param [in] result The index of the item selected by the user.
202  * [in] headerBlock Pointer to the header block.
203  */
204  void AudioProcessorEditor::menuCallback(int result, UIHeaderBlock* headerBlock)
205  {
206  if (headerBlock != nullptr && result != 0)
207  {
208  auto irName = headerBlock->parameters.state.getChildWithName(AudioProcessor::PID_IR_FILE_CHOICE);
209  juce::String selectedIR;
210  if (result == 1)
211  {
212  juce::AudioFormatManager formatManager;
213  formatManager.registerBasicFormats();
214  // Accepts the following file types: .wav, .bwf, .aiff, .flac, .ogg, .mp3, .wmv, .asf, .wm, .wma
215  juce::FileChooser fileChooser("Select an impulse response",
216  juce::File::getCurrentWorkingDirectory(),
217  formatManager.getWildcardForAllFormats(),
218  false);
219  if (fileChooser.browseForFileToOpen())
220  {
221  selectedIR = fileChooser.getResult().getFullPathName();
222  irName.setProperty("value", selectedIR, nullptr);
223  headerBlock->irChoice.setButtonText(selectedIR);
224  headerBlock->previousSelectedIRs.add(selectedIR);
225  }
226  }
227  else if (result <= (headerBlock->previousSelectedIRs.size() + 1))
228  {
229  selectedIR = headerBlock->previousSelectedIRs[result - 2];
230  irName.setProperty("value", selectedIR, nullptr);
231  headerBlock->irChoice.setButtonText(selectedIR);
232  }
233  else
234  {
235  selectedIR = std::next(IRBank::getInstance().buffers.begin(),
236  result - headerBlock->previousSelectedIRs.size() - 2)->first;
237  irName.setProperty("value", selectedIR, nullptr);
238  headerBlock->irChoice.setButtonText(selectedIR);
239  }
240  }
241  }
242 
243 }
AudioProcessorEditor(AudioProcessor &)
Constructs an AudioProcessorEditor object associated with an AudioProcessor.
float getParam(const juce::AudioProcessorValueTreeState &params, const juce::String &blockId) const
Internal method used to get (and check) a parameter&#39;s value.
Definition: Task.h:111
void buttonClicked(juce::Button *button) override
Callback function to open the popup menu asynchronously.
void resized() override
Manages the layout of AudioProcessorEditor when the window is resized.
static void menuCallback(int result, UIHeaderBlock *headerBlock)
Callback function to open the popup menu asynchronously.