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() {
|
||||
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;
|
||||
int index = audioProcessor.getCurrentFileIndex();
|
||||
if (index != -1) {
|
||||
|
|
|
@ -444,9 +444,12 @@ void OscirenderAudioProcessor::processBlock (juce::AudioBuffer<float>& buffer, j
|
|||
x = channels.x;
|
||||
y = channels.y;
|
||||
|
||||
// clip to -1.0 to 1.0
|
||||
x = std::max(-1.0, std::min(1.0, x));
|
||||
y = std::max(-1.0, std::min(1.0, y));
|
||||
x *= volume;
|
||||
y *= volume;
|
||||
|
||||
// clip
|
||||
x = std::max(-threshold, std::min(threshold.load(), x));
|
||||
y = std::max(-threshold, std::min(threshold.load(), y));
|
||||
|
||||
if (totalNumOutputChannels >= 2) {
|
||||
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() {
|
||||
|
|
|
@ -64,10 +64,11 @@ public:
|
|||
void getStateInformation (juce::MemoryBlock& destData) override;
|
||||
void setStateInformation (const void* data, int sizeInBytes) override;
|
||||
|
||||
float noteOnVel;
|
||||
float frequency = 440.0f;
|
||||
std::atomic<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;
|
||||
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::trackColourId, juce::Colours::transparentWhite);
|
||||
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);
|
||||
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.setOpaque(false);
|
||||
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() {
|
||||
|
@ -30,6 +44,8 @@ VolumeComponent::~VolumeComponent() {
|
|||
void VolumeComponent::paint(juce::Graphics& g) {
|
||||
auto r = getLocalBounds().toFloat();
|
||||
r.removeFromRight(r.getWidth() / 2);
|
||||
r.removeFromTop(volumeSlider.getLookAndFeel().getSliderThumbRadius(volumeSlider));
|
||||
r.removeFromBottom(volumeSlider.getLookAndFeel().getSliderThumbRadius(volumeSlider));
|
||||
|
||||
g.setColour(juce::Colours::white);
|
||||
g.fillRect(r);
|
||||
|
@ -43,17 +59,19 @@ void VolumeComponent::paint(juce::Graphics& g) {
|
|||
auto leftRegion = leftRect;
|
||||
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.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));
|
||||
|
||||
// draw average volume as new rectangles on each channel 10 pixels tall
|
||||
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);
|
||||
auto barWidth = 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() {
|
||||
|
|
|
@ -4,6 +4,60 @@
|
|||
#include "../concurrency/BufferConsumer.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 {
|
||||
public:
|
||||
VolumeComponent(OscirenderAudioProcessor& p);
|
||||
|
@ -22,8 +76,10 @@ private:
|
|||
std::atomic<float> rightVolume = 0;
|
||||
std::atomic<float> avgLeftVolume = 0;
|
||||
std::atomic<float> avgRightVolume = 0;
|
||||
|
||||
juce::Slider volumeSlider;
|
||||
|
||||
ThumbRadiusLookAndFeel thumbRadiusLookAndFeel{20};
|
||||
juce::Slider volumeSlider;
|
||||
ThresholdLookAndFeel thresholdLookAndFeel{20};
|
||||
juce::Slider thresholdSlider;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(VolumeComponent)
|
||||
|
|
Ładowanie…
Reference in New Issue