kopia lustrzana https://github.com/jameshball/osci-render
Create fully-functioning and somewhat good looking volume visualiser
rodzic
afdd4483b3
commit
c0e64094aa
|
@ -56,7 +56,9 @@ void OscirenderAudioProcessorEditor::paint(juce::Graphics& g)
|
||||||
|
|
||||||
void OscirenderAudioProcessorEditor::resized() {
|
void OscirenderAudioProcessorEditor::resized() {
|
||||||
auto area = getLocalBounds();
|
auto area = getLocalBounds();
|
||||||
volume.setBounds(area.removeFromLeft(50));
|
area.removeFromLeft(5);
|
||||||
|
auto volumeArea = area.removeFromLeft(30);
|
||||||
|
volume.setBounds(volumeArea.withSizeKeepingCentre(volumeArea.getWidth(), std::min(volumeArea.getHeight(), 300)));
|
||||||
auto sections = 2;
|
auto sections = 2;
|
||||||
int index = audioProcessor.getCurrentFileIndex();
|
int index = audioProcessor.getCurrentFileIndex();
|
||||||
if (index != -1) {
|
if (index != -1) {
|
||||||
|
|
|
@ -444,9 +444,12 @@ void OscirenderAudioProcessor::processBlock (juce::AudioBuffer<float>& buffer, j
|
||||||
x = channels.x;
|
x = channels.x;
|
||||||
y = channels.y;
|
y = channels.y;
|
||||||
|
|
||||||
// clip to -1.0 to 1.0
|
x *= volume;
|
||||||
x = std::max(-1.0, std::min(1.0, x));
|
y *= volume;
|
||||||
y = std::max(-1.0, std::min(1.0, y));
|
|
||||||
|
// clip
|
||||||
|
x = std::max(-threshold, std::min(threshold.load(), x));
|
||||||
|
y = std::max(-threshold, std::min(threshold.load(), y));
|
||||||
|
|
||||||
if (totalNumOutputChannels >= 2) {
|
if (totalNumOutputChannels >= 2) {
|
||||||
channelData[0][sample] = x;
|
channelData[0][sample] = x;
|
||||||
|
@ -475,19 +478,6 @@ void OscirenderAudioProcessor::processBlock (juce::AudioBuffer<float>& buffer, j
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
juce::MidiBuffer processedMidi;
|
|
||||||
|
|
||||||
for (const auto metadata : midiMessages) {
|
|
||||||
auto message = metadata.getMessage();
|
|
||||||
const auto time = metadata.samplePosition;
|
|
||||||
|
|
||||||
if (message.isNoteOn()) {
|
|
||||||
message = juce::MidiMessage::noteOn(message.getChannel(), message.getNoteNumber(), (juce::uint8)noteOnVel);
|
|
||||||
}
|
|
||||||
processedMidi.addEvent(message, time);
|
|
||||||
}
|
|
||||||
midiMessages.swapWith(processedMidi);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void OscirenderAudioProcessor::incrementShapeDrawing() {
|
void OscirenderAudioProcessor::incrementShapeDrawing() {
|
||||||
|
|
|
@ -64,10 +64,11 @@ public:
|
||||||
void getStateInformation (juce::MemoryBlock& destData) override;
|
void getStateInformation (juce::MemoryBlock& destData) override;
|
||||||
void setStateInformation (const void* data, int sizeInBytes) override;
|
void setStateInformation (const void* data, int sizeInBytes) override;
|
||||||
|
|
||||||
float noteOnVel;
|
std::atomic<float> frequency = 440.0f;
|
||||||
float frequency = 440.0f;
|
std::atomic<double> volume = 1.0;
|
||||||
|
std::atomic<double> threshold = 1.0;
|
||||||
|
|
||||||
double currentSampleRate = 0.0;
|
std::atomic<double> currentSampleRate = 0.0;
|
||||||
|
|
||||||
juce::SpinLock effectsLock;
|
juce::SpinLock effectsLock;
|
||||||
std::vector<std::shared_ptr<Effect>> allEffects;
|
std::vector<std::shared_ptr<Effect>> allEffects;
|
||||||
|
|
|
@ -11,7 +11,10 @@ VolumeComponent::VolumeComponent(OscirenderAudioProcessor& p) : audioProcessor(p
|
||||||
volumeSlider.setColour(juce::Slider::ColourIds::backgroundColourId, juce::Colours::transparentWhite);
|
volumeSlider.setColour(juce::Slider::ColourIds::backgroundColourId, juce::Colours::transparentWhite);
|
||||||
volumeSlider.setColour(juce::Slider::ColourIds::trackColourId, juce::Colours::transparentWhite);
|
volumeSlider.setColour(juce::Slider::ColourIds::trackColourId, juce::Colours::transparentWhite);
|
||||||
volumeSlider.setOpaque(false);
|
volumeSlider.setOpaque(false);
|
||||||
volumeSlider.setRange(0, 1, 0.001);
|
volumeSlider.setRange(0, 2, 0.001);
|
||||||
|
volumeSlider.setValue(1);
|
||||||
|
volumeSlider.setLookAndFeel(&thumbRadiusLookAndFeel);
|
||||||
|
volumeSlider.setColour(juce::Slider::ColourIds::thumbColourId, juce::Colours::black);
|
||||||
|
|
||||||
addAndMakeVisible(thresholdSlider);
|
addAndMakeVisible(thresholdSlider);
|
||||||
thresholdSlider.setSliderStyle(juce::Slider::SliderStyle::LinearVertical);
|
thresholdSlider.setSliderStyle(juce::Slider::SliderStyle::LinearVertical);
|
||||||
|
@ -20,6 +23,17 @@ VolumeComponent::VolumeComponent(OscirenderAudioProcessor& p) : audioProcessor(p
|
||||||
thresholdSlider.setColour(juce::Slider::ColourIds::trackColourId, juce::Colours::transparentWhite);
|
thresholdSlider.setColour(juce::Slider::ColourIds::trackColourId, juce::Colours::transparentWhite);
|
||||||
thresholdSlider.setOpaque(false);
|
thresholdSlider.setOpaque(false);
|
||||||
thresholdSlider.setRange(0, 1, 0.001);
|
thresholdSlider.setRange(0, 1, 0.001);
|
||||||
|
thresholdSlider.setValue(1);
|
||||||
|
thresholdSlider.setLookAndFeel(&thresholdLookAndFeel);
|
||||||
|
thresholdSlider.setColour(juce::Slider::ColourIds::thumbColourId, juce::Colours::black);
|
||||||
|
|
||||||
|
volumeSlider.onValueChange = [this]() {
|
||||||
|
audioProcessor.volume = volumeSlider.getValue();
|
||||||
|
};
|
||||||
|
|
||||||
|
thresholdSlider.onValueChange = [this]() {
|
||||||
|
audioProcessor.threshold = thresholdSlider.getValue();
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
VolumeComponent::~VolumeComponent() {
|
VolumeComponent::~VolumeComponent() {
|
||||||
|
@ -30,6 +44,8 @@ VolumeComponent::~VolumeComponent() {
|
||||||
void VolumeComponent::paint(juce::Graphics& g) {
|
void VolumeComponent::paint(juce::Graphics& g) {
|
||||||
auto r = getLocalBounds().toFloat();
|
auto r = getLocalBounds().toFloat();
|
||||||
r.removeFromRight(r.getWidth() / 2);
|
r.removeFromRight(r.getWidth() / 2);
|
||||||
|
r.removeFromTop(volumeSlider.getLookAndFeel().getSliderThumbRadius(volumeSlider));
|
||||||
|
r.removeFromBottom(volumeSlider.getLookAndFeel().getSliderThumbRadius(volumeSlider));
|
||||||
|
|
||||||
g.setColour(juce::Colours::white);
|
g.setColour(juce::Colours::white);
|
||||||
g.fillRect(r);
|
g.fillRect(r);
|
||||||
|
@ -43,17 +59,19 @@ void VolumeComponent::paint(juce::Graphics& g) {
|
||||||
auto leftRegion = leftRect;
|
auto leftRegion = leftRect;
|
||||||
auto rightRegion = rightRect;
|
auto rightRegion = rightRect;
|
||||||
|
|
||||||
g.setGradientFill(juce::ColourGradient(juce::Colours::green, 0, leftRect.getBottom(), juce::Colours::red, 0, leftRect.getY(), false));
|
g.setGradientFill(juce::ColourGradient(juce::Colour(0xff00ff00), 0, leftRect.getBottom(), juce::Colours::red, 0, leftRect.getY(), false));
|
||||||
g.fillRect(leftRect.removeFromBottom(leftVolumeHeight));
|
g.fillRect(leftRect.removeFromBottom(leftVolumeHeight));
|
||||||
|
|
||||||
g.setGradientFill(juce::ColourGradient(juce::Colours::green, 0, rightRect.getBottom(), juce::Colours::red, 0, rightRect.getY(), false));
|
g.setGradientFill(juce::ColourGradient(juce::Colour(0xff00ff00), 0, rightRect.getBottom(), juce::Colours::red, 0, rightRect.getY(), false));
|
||||||
g.fillRect(rightRect.removeFromBottom(rightVolumeHeight));
|
g.fillRect(rightRect.removeFromBottom(rightVolumeHeight));
|
||||||
|
|
||||||
// draw average volume as new rectangles on each channel 10 pixels tall
|
auto barWidth = 5.0f;
|
||||||
g.setColour(juce::Colours::black);
|
|
||||||
g.fillRect(leftRegion.getX(), leftRegion.getBottom() - (avgLeftVolume * channelHeight), leftRegion.getWidth(), 5.0f);
|
|
||||||
g.fillRect(rightRegion.getX(), rightRegion.getBottom() - (avgRightVolume * channelHeight), rightRegion.getWidth(), 5.0f);
|
|
||||||
|
|
||||||
|
g.setColour(juce::Colours::black);
|
||||||
|
g.fillRect(leftRegion.getX(), leftRegion.getBottom() - (avgLeftVolume * channelHeight) - barWidth / 2, leftRegion.getWidth(), barWidth);
|
||||||
|
g.fillRect(rightRegion.getX(), rightRegion.getBottom() - (avgRightVolume * channelHeight) - barWidth / 2, rightRegion.getWidth(), barWidth);
|
||||||
|
|
||||||
|
g.fillRect(leftRegion.getX(), rightRegion.getBottom() - (thresholdSlider.getValue() * channelHeight) - barWidth / 2, leftRegion.getWidth() + rightRegion.getWidth(), barWidth);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VolumeComponent::timerCallback() {
|
void VolumeComponent::timerCallback() {
|
||||||
|
|
|
@ -4,6 +4,60 @@
|
||||||
#include "../concurrency/BufferConsumer.h"
|
#include "../concurrency/BufferConsumer.h"
|
||||||
#include "../PluginProcessor.h"
|
#include "../PluginProcessor.h"
|
||||||
|
|
||||||
|
class ThumbRadiusLookAndFeel : public juce::LookAndFeel_V4 {
|
||||||
|
public:
|
||||||
|
ThumbRadiusLookAndFeel(int thumbRadius) : thumbRadius(thumbRadius) {}
|
||||||
|
|
||||||
|
int getSliderThumbRadius(juce::Slider& slider) override {
|
||||||
|
return juce::jmin(thumbRadius, slider.isHorizontal() ? slider.getHeight() : slider.getWidth());
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
int thumbRadius = 12;
|
||||||
|
};
|
||||||
|
|
||||||
|
// this is for a vertical slider
|
||||||
|
class ThresholdLookAndFeel : public ThumbRadiusLookAndFeel {
|
||||||
|
public:
|
||||||
|
ThresholdLookAndFeel(int thumbRadius) : ThumbRadiusLookAndFeel(thumbRadius) {}
|
||||||
|
|
||||||
|
void drawLinearSliderThumb(juce::Graphics& g, int x, int y, int width, int height, float sliderPos, float minSliderPos, float maxSliderPos, const juce::Slider::SliderStyle style, juce::Slider& slider) override {
|
||||||
|
float kx = (float) x + (float) width * 0.5f;
|
||||||
|
float ky = sliderPos;
|
||||||
|
|
||||||
|
auto outlineThickness = slider.isEnabled() ? 0.8f : 0.3f;
|
||||||
|
auto sliderRadius = (float) (getSliderThumbRadius(slider) - 2);
|
||||||
|
auto diameter = sliderRadius * 2.0f;
|
||||||
|
auto halfThickness = outlineThickness * 0.5f;
|
||||||
|
|
||||||
|
auto isDownOrDragging = slider.isEnabled() && (slider.isMouseOverOrDragging() || slider.isMouseButtonDown());
|
||||||
|
|
||||||
|
auto knobColour = slider.findColour(juce::Slider::thumbColourId)
|
||||||
|
.withMultipliedSaturation((slider.hasKeyboardFocus (false) || isDownOrDragging) ? 1.3f : 0.9f)
|
||||||
|
.withMultipliedAlpha(slider.isEnabled() ? 1.0f : 0.7f);
|
||||||
|
|
||||||
|
y = (int) (ky - sliderRadius);
|
||||||
|
|
||||||
|
// draw triangle that points left
|
||||||
|
juce::Path p;
|
||||||
|
p.addTriangle(
|
||||||
|
x + diameter, y,
|
||||||
|
x + diameter, y + diameter,
|
||||||
|
x, ky
|
||||||
|
);
|
||||||
|
|
||||||
|
g.setColour(knobColour);
|
||||||
|
g.fillPath(p);
|
||||||
|
|
||||||
|
g.setColour(knobColour.brighter());
|
||||||
|
g.strokePath(p, juce::PathStrokeType(outlineThickness));
|
||||||
|
}
|
||||||
|
|
||||||
|
void drawLinearSlider(juce::Graphics& g, int x, int y, int width, int height, float sliderPos, float minSliderPos, float maxSliderPos, const juce::Slider::SliderStyle style, juce::Slider& slider) override {
|
||||||
|
drawLinearSliderThumb(g, x, y, width, height, sliderPos, minSliderPos, maxSliderPos, style, slider);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
class VolumeComponent : public juce::Component, public juce::Timer, public juce::Thread {
|
class VolumeComponent : public juce::Component, public juce::Timer, public juce::Thread {
|
||||||
public:
|
public:
|
||||||
VolumeComponent(OscirenderAudioProcessor& p);
|
VolumeComponent(OscirenderAudioProcessor& p);
|
||||||
|
@ -22,8 +76,10 @@ private:
|
||||||
std::atomic<float> rightVolume = 0;
|
std::atomic<float> rightVolume = 0;
|
||||||
std::atomic<float> avgLeftVolume = 0;
|
std::atomic<float> avgLeftVolume = 0;
|
||||||
std::atomic<float> avgRightVolume = 0;
|
std::atomic<float> avgRightVolume = 0;
|
||||||
|
|
||||||
juce::Slider volumeSlider;
|
ThumbRadiusLookAndFeel thumbRadiusLookAndFeel{20};
|
||||||
|
juce::Slider volumeSlider;
|
||||||
|
ThresholdLookAndFeel thresholdLookAndFeel{20};
|
||||||
juce::Slider thresholdSlider;
|
juce::Slider thresholdSlider;
|
||||||
|
|
||||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(VolumeComponent)
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(VolumeComponent)
|
||||||
|
|
Ładowanie…
Reference in New Issue