23 : processor(processor),
juce::
GroupComponent(
"IR Graph",
"waveform - impulse response")
25 graphThread.reset(
new std::thread(&UIGraphBlock::updateGraph,
this, 100));
36 stopGraphThread =
true;
37 mustUpdate.notify_all();
45 g.fillAll(getLookAndFeel().findColour(juce::ResizableWindow::backgroundColourId));
47 g.setColour(juce::Colours::white);
50 g.setColour(juce::Colour(0xddffffff));
52 for (
auto& irPlot : irChannelPlots)
54 g.strokePath(irPlot, juce::PathStrokeType(1.0f));
57 juce::Rectangle<
int> bounds(getLocalBounds());
58 getLookAndFeel().drawGroupComponentOutline(g, bounds.getWidth(), bounds.getHeight(), getText(),
59 juce::Justification(juce::Justification::centredTop), *
this);
71 juce::Rectangle<
int> bounds(getLocalBounds());
72 int padding = (
int)std::round(bounds.getHeight() * AudioProcessorEditor::PADDING_REL);
74 bounds.reduce(4*padding, 4*padding);
77 float x = (
float)bounds.getX();
78 float width = (
float)bounds.getWidth();
80 float height = (
float)bounds.getHeight();
81 float yCentre = (
float)bounds.getCentreY();
84 irChannelPlots.clear();
86 for (
int channel = 0; channel < processor.mainPipelines.size(); ++channel)
89 AudioBlock ir = processor.mainPipelines[channel]->ir;
90 double sampleRate = processor.mainPipelines[channel]->sampleRate;
92 int samplesPerStep = (
int)std::ceil(GRAPH_TIME_STEP_S * sampleRate);
93 int numSteps = (
int)std::ceil(GRAPH_TOTAL_TIME_S / GRAPH_TIME_STEP_S);
95 float xScale = width / numSteps;
96 float yScale = height;
99 irChannelPlots.emplace_back();
100 auto& irPlot = irChannelPlots.back();
102 float * irSamples = ir.getChannelPointer(0);
105 irPlot.preallocateSpace(numSteps);
108 irPlot.startNewSubPath(x, irSamples[0] + yCentre);
111 int numStepsInIR = (
int)ir.getNumSamples() / samplesPerStep;
112 std::vector<
float> maxValues(numStepsInIR, 0.0f);
114 auto cmpAbsMax = [](
float f1,
float f2) {
return std::abs(f1) < std::abs(f2); };
116 for (
int step = 0; step < numStepsInIR; ++step)
118 float * start = irSamples + step * samplesPerStep;
119 float * end = start + samplesPerStep;
121 maxValues[step] = *std::max_element(start, end, cmpAbsMax);
125 for (
int step = 0; step < numStepsInIR; step++)
127 irPlot.lineTo(x + step * xScale, yCentre + maxValues[step] * yScale);
131 irPlot.lineTo(x + numStepsInIR * xScale, yCentre);
132 irPlot.lineTo(x + numSteps * xScale, yCentre);
148 std::unique_lock<std::mutex> lock(updatingGraph);
150 while (!stopGraphThread)
153 juce::Component::SafePointer<juce::Component> sp(
this);
156 juce::MessageManager::callAsync(
159 if (!sp.getComponent())
164 UIGraphBlock * gb =
dynamic_cast<UIGraphBlock*>(sp.getComponent());
172 std::lock_guard<std::mutex> paramsLock(gb->getProcessorInstance()->updatingParams);
175 std::unique_lock<std::mutex> lock(gb->updatingGraph);
181 gb->updateComplete.notify_all();
186 updateComplete.wait_for(lock, std::chrono::milliseconds(updatePeriodMs));
189 mustUpdate.wait_for(lock, std::chrono::milliseconds(updatePeriodMs));
201 mustUpdate.notify_one();
float getParam(const juce::AudioProcessorValueTreeState ¶ms, const juce::String &blockId) const
Internal method used to get (and check) a parameter's value.
~UIGraphBlock()
Destroys a UIGraphBlock object.
void notifyToUpdate()
Signals thread to update graph.
void resized() override
Manages the layout of UIGraphBlock when the block is resized.
UIGraphBlock(AudioProcessor &processor)
Constructs a UIGraphBlock object.
void updateGraph(int updatePeriodMs)
Updates IR graph.