kopia lustrzana https://github.com/jameshball/osci-render
Add basic volume visualiser with non-functioning sliders
rodzic
0a922847b4
commit
afdd4483b3
|
@ -79,17 +79,10 @@ MainComponent::MainComponent(OscirenderAudioProcessor& p, OscirenderAudioProcess
|
||||||
};
|
};
|
||||||
|
|
||||||
addAndMakeVisible(visualiser);
|
addAndMakeVisible(visualiser);
|
||||||
audioProcessor.audioProducer.registerConsumer(consumer);
|
|
||||||
visualiserProcessor.startThread();
|
|
||||||
|
|
||||||
addAndMakeVisible(frequencyLabel);
|
addAndMakeVisible(frequencyLabel);
|
||||||
pitchDetector.startThread();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MainComponent::~MainComponent() {
|
MainComponent::~MainComponent() {}
|
||||||
audioProcessor.audioProducer.unregisterConsumer(consumer);
|
|
||||||
visualiserProcessor.stopThread(1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
void MainComponent::updateFileLabel() {
|
void MainComponent::updateFileLabel() {
|
||||||
if (audioProcessor.getCurrentFileIndex() == -1) {
|
if (audioProcessor.getCurrentFileIndex() == -1) {
|
||||||
|
|
|
@ -29,8 +29,6 @@ private:
|
||||||
juce::TextButton createFile{"Create File"};
|
juce::TextButton createFile{"Create File"};
|
||||||
|
|
||||||
VisualiserComponent visualiser{2, audioProcessor};
|
VisualiserComponent visualiser{2, audioProcessor};
|
||||||
std::shared_ptr<BufferConsumer> consumer = std::make_shared<BufferConsumer>(2048);
|
|
||||||
VisualiserProcessor visualiserProcessor{consumer, visualiser};
|
|
||||||
|
|
||||||
juce::Label frequencyLabel;
|
juce::Label frequencyLabel;
|
||||||
PitchDetector pitchDetector{
|
PitchDetector pitchDetector{
|
||||||
|
|
|
@ -1,22 +1,14 @@
|
||||||
/*
|
|
||||||
==============================================================================
|
|
||||||
|
|
||||||
This file contains the basic framework code for a JUCE plugin editor.
|
|
||||||
|
|
||||||
==============================================================================
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "PluginProcessor.h"
|
#include "PluginProcessor.h"
|
||||||
#include "PluginEditor.h"
|
#include "PluginEditor.h"
|
||||||
|
|
||||||
//==============================================================================
|
|
||||||
OscirenderAudioProcessorEditor::OscirenderAudioProcessorEditor(OscirenderAudioProcessor& p)
|
OscirenderAudioProcessorEditor::OscirenderAudioProcessorEditor(OscirenderAudioProcessor& p)
|
||||||
: AudioProcessorEditor(&p), audioProcessor(p), effects(p), main(p, *this), collapseButton("Collapse", juce::Colours::white, juce::Colours::white, juce::Colours::white), lua(p, *this), obj(p, *this)
|
: AudioProcessorEditor(&p), audioProcessor(p), collapseButton("Collapse", juce::Colours::white, juce::Colours::white, juce::Colours::white)
|
||||||
{
|
{
|
||||||
addAndMakeVisible(effects);
|
addAndMakeVisible(effects);
|
||||||
addAndMakeVisible(main);
|
addAndMakeVisible(main);
|
||||||
addChildComponent(lua);
|
addChildComponent(lua);
|
||||||
addChildComponent(obj);
|
addChildComponent(obj);
|
||||||
|
addAndMakeVisible(volume);
|
||||||
|
|
||||||
addAndMakeVisible(collapseButton);
|
addAndMakeVisible(collapseButton);
|
||||||
collapseButton.onClick = [this] {
|
collapseButton.onClick = [this] {
|
||||||
|
@ -54,8 +46,7 @@ OscirenderAudioProcessorEditor::OscirenderAudioProcessorEditor(OscirenderAudioPr
|
||||||
|
|
||||||
OscirenderAudioProcessorEditor::~OscirenderAudioProcessorEditor() {}
|
OscirenderAudioProcessorEditor::~OscirenderAudioProcessorEditor() {}
|
||||||
|
|
||||||
//==============================================================================
|
void OscirenderAudioProcessorEditor::paint(juce::Graphics& g)
|
||||||
void OscirenderAudioProcessorEditor::paint (juce::Graphics& g)
|
|
||||||
{
|
{
|
||||||
g.fillAll(getLookAndFeel().findColour(juce::ResizableWindow::backgroundColourId));
|
g.fillAll(getLookAndFeel().findColour(juce::ResizableWindow::backgroundColourId));
|
||||||
|
|
||||||
|
@ -65,6 +56,7 @@ void OscirenderAudioProcessorEditor::paint (juce::Graphics& g)
|
||||||
|
|
||||||
void OscirenderAudioProcessorEditor::resized() {
|
void OscirenderAudioProcessorEditor::resized() {
|
||||||
auto area = getLocalBounds();
|
auto area = getLocalBounds();
|
||||||
|
volume.setBounds(area.removeFromLeft(50));
|
||||||
auto sections = 2;
|
auto sections = 2;
|
||||||
int index = audioProcessor.getCurrentFileIndex();
|
int index = audioProcessor.getCurrentFileIndex();
|
||||||
if (index != -1) {
|
if (index != -1) {
|
||||||
|
|
|
@ -6,14 +6,15 @@
|
||||||
#include "MainComponent.h"
|
#include "MainComponent.h"
|
||||||
#include "LuaComponent.h"
|
#include "LuaComponent.h"
|
||||||
#include "ObjComponent.h"
|
#include "ObjComponent.h"
|
||||||
|
#include "components/VolumeComponent.h"
|
||||||
|
|
||||||
|
|
||||||
class OscirenderAudioProcessorEditor : public juce::AudioProcessorEditor, private juce::CodeDocument::Listener {
|
class OscirenderAudioProcessorEditor : public juce::AudioProcessorEditor, private juce::CodeDocument::Listener {
|
||||||
public:
|
public:
|
||||||
OscirenderAudioProcessorEditor (OscirenderAudioProcessor&);
|
OscirenderAudioProcessorEditor(OscirenderAudioProcessor&);
|
||||||
~OscirenderAudioProcessorEditor() override;
|
~OscirenderAudioProcessorEditor() override;
|
||||||
|
|
||||||
void paint (juce::Graphics&) override;
|
void paint(juce::Graphics&) override;
|
||||||
void resized() override;
|
void resized() override;
|
||||||
|
|
||||||
void addCodeEditor(int index);
|
void addCodeEditor(int index);
|
||||||
|
@ -22,10 +23,11 @@ public:
|
||||||
private:
|
private:
|
||||||
OscirenderAudioProcessor& audioProcessor;
|
OscirenderAudioProcessor& audioProcessor;
|
||||||
|
|
||||||
MainComponent main;
|
MainComponent main{audioProcessor, *this};
|
||||||
LuaComponent lua;
|
LuaComponent lua{audioProcessor, *this};
|
||||||
ObjComponent obj;
|
ObjComponent obj{audioProcessor, *this};
|
||||||
EffectsComponent effects;
|
EffectsComponent effects{audioProcessor};
|
||||||
|
VolumeComponent volume{audioProcessor};
|
||||||
std::vector<std::shared_ptr<juce::CodeDocument>> codeDocuments;
|
std::vector<std::shared_ptr<juce::CodeDocument>> codeDocuments;
|
||||||
std::vector<std::shared_ptr<juce::CodeEditorComponent>> codeEditors;
|
std::vector<std::shared_ptr<juce::CodeEditorComponent>> codeEditors;
|
||||||
juce::LuaTokeniser luaTokeniser;
|
juce::LuaTokeniser luaTokeniser;
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
#include "PitchDetector.h"
|
#include "PitchDetector.h"
|
||||||
#include "PitchDetector.h"
|
#include "PitchDetector.h"
|
||||||
|
|
||||||
PitchDetector::PitchDetector(OscirenderAudioProcessor& p, std::function<void(float)> frequencyCallback) : juce::Thread("PitchDetector"), audioProcessor(p), frequencyCallback(frequencyCallback) {}
|
PitchDetector::PitchDetector(OscirenderAudioProcessor& p, std::function<void(float)> frequencyCallback) : juce::Thread("PitchDetector"), audioProcessor(p), frequencyCallback(frequencyCallback) {
|
||||||
|
startThread();
|
||||||
|
}
|
||||||
|
|
||||||
PitchDetector::~PitchDetector() {
|
PitchDetector::~PitchDetector() {
|
||||||
audioProcessor.audioProducer.unregisterConsumer(consumer);
|
audioProcessor.audioProducer.unregisterConsumer(consumer);
|
||||||
|
|
|
@ -1,11 +1,15 @@
|
||||||
#include "VisualiserComponent.h"
|
#include "VisualiserComponent.h"
|
||||||
|
|
||||||
VisualiserComponent::VisualiserComponent(int numChannels, OscirenderAudioProcessor& p) : numChannels(numChannels), backgroundColour(juce::Colours::black), waveformColour(juce::Colour(0xff00ff00)), audioProcessor(p) {
|
VisualiserComponent::VisualiserComponent(int numChannels, OscirenderAudioProcessor& p) : numChannels(numChannels), backgroundColour(juce::Colours::black), waveformColour(juce::Colour(0xff00ff00)), audioProcessor(p), juce::Thread("VisualiserComponent") {
|
||||||
setOpaque(true);
|
setOpaque(true);
|
||||||
startTimerHz(60);
|
startTimerHz(60);
|
||||||
|
startThread();
|
||||||
}
|
}
|
||||||
|
|
||||||
VisualiserComponent::~VisualiserComponent() {}
|
VisualiserComponent::~VisualiserComponent() {
|
||||||
|
audioProcessor.audioProducer.unregisterConsumer(consumer);
|
||||||
|
stopThread(1000);
|
||||||
|
}
|
||||||
|
|
||||||
void VisualiserComponent::setBuffer(std::vector<float>& newBuffer) {
|
void VisualiserComponent::setBuffer(std::vector<float>& newBuffer) {
|
||||||
juce::SpinLock::ScopedLockType scope(lock);
|
juce::SpinLock::ScopedLockType scope(lock);
|
||||||
|
@ -40,6 +44,16 @@ void VisualiserComponent::timerCallback() {
|
||||||
repaint();
|
repaint();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VisualiserComponent::run() {
|
||||||
|
audioProcessor.audioProducer.registerConsumer(consumer);
|
||||||
|
|
||||||
|
while (!threadShouldExit()) {
|
||||||
|
auto buffer = consumer->startProcessing();
|
||||||
|
setBuffer(*buffer);
|
||||||
|
consumer->finishedProcessing();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void VisualiserComponent::paintChannel(juce::Graphics& g, juce::Rectangle<float> area, int channel) {
|
void VisualiserComponent::paintChannel(juce::Graphics& g, juce::Rectangle<float> area, int channel) {
|
||||||
juce::Path path;
|
juce::Path path;
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
#include "../concurrency/BufferConsumer.h"
|
#include "../concurrency/BufferConsumer.h"
|
||||||
#include "../PluginProcessor.h"
|
#include "../PluginProcessor.h"
|
||||||
|
|
||||||
class VisualiserComponent : public juce::Component, public juce::Timer {
|
class VisualiserComponent : public juce::Component, public juce::Timer, public juce::Thread {
|
||||||
public:
|
public:
|
||||||
VisualiserComponent(int numChannels, OscirenderAudioProcessor& p);
|
VisualiserComponent(int numChannels, OscirenderAudioProcessor& p);
|
||||||
~VisualiserComponent() override;
|
~VisualiserComponent() override;
|
||||||
|
@ -15,6 +15,7 @@ public:
|
||||||
void paintXY(juce::Graphics&, juce::Rectangle<float> bounds);
|
void paintXY(juce::Graphics&, juce::Rectangle<float> bounds);
|
||||||
void paint(juce::Graphics&) override;
|
void paint(juce::Graphics&) override;
|
||||||
void timerCallback() override;
|
void timerCallback() override;
|
||||||
|
void run() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
juce::SpinLock lock;
|
juce::SpinLock lock;
|
||||||
|
@ -22,26 +23,8 @@ private:
|
||||||
int numChannels = 2;
|
int numChannels = 2;
|
||||||
juce::Colour backgroundColour, waveformColour;
|
juce::Colour backgroundColour, waveformColour;
|
||||||
OscirenderAudioProcessor& audioProcessor;
|
OscirenderAudioProcessor& audioProcessor;
|
||||||
|
std::shared_ptr<BufferConsumer> consumer = std::make_shared<BufferConsumer>(2048);
|
||||||
int precision = 2;
|
int precision = 2;
|
||||||
|
|
||||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(VisualiserComponent)
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(VisualiserComponent)
|
||||||
};
|
|
||||||
|
|
||||||
class VisualiserProcessor : public juce::Thread {
|
|
||||||
public:
|
|
||||||
VisualiserProcessor(std::shared_ptr<BufferConsumer> consumer, VisualiserComponent& visualiser) : juce::Thread("VisualiserProcessor"), consumer(consumer), visualiser(visualiser) {}
|
|
||||||
~VisualiserProcessor() override {}
|
|
||||||
|
|
||||||
void run() override {
|
|
||||||
while (!threadShouldExit()) {
|
|
||||||
auto buffer = consumer->startProcessing();
|
|
||||||
|
|
||||||
visualiser.setBuffer(*buffer);
|
|
||||||
consumer->finishedProcessing();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::shared_ptr<BufferConsumer> consumer;
|
|
||||||
VisualiserComponent& visualiser;
|
|
||||||
};
|
};
|
|
@ -0,0 +1,95 @@
|
||||||
|
#include "VolumeComponent.h"
|
||||||
|
|
||||||
|
VolumeComponent::VolumeComponent(OscirenderAudioProcessor& p) : audioProcessor(p), juce::Thread("VolumeComponent") {
|
||||||
|
setOpaque(false);
|
||||||
|
startTimerHz(60);
|
||||||
|
startThread();
|
||||||
|
|
||||||
|
addAndMakeVisible(volumeSlider);
|
||||||
|
volumeSlider.setSliderStyle(juce::Slider::SliderStyle::LinearVertical);
|
||||||
|
volumeSlider.setTextBoxStyle(juce::Slider::NoTextBox, true, 0, 0);
|
||||||
|
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);
|
||||||
|
|
||||||
|
addAndMakeVisible(thresholdSlider);
|
||||||
|
thresholdSlider.setSliderStyle(juce::Slider::SliderStyle::LinearVertical);
|
||||||
|
thresholdSlider.setTextBoxStyle(juce::Slider::NoTextBox, true, 0, 0);
|
||||||
|
thresholdSlider.setColour(juce::Slider::ColourIds::backgroundColourId, juce::Colours::transparentWhite);
|
||||||
|
thresholdSlider.setColour(juce::Slider::ColourIds::trackColourId, juce::Colours::transparentWhite);
|
||||||
|
thresholdSlider.setOpaque(false);
|
||||||
|
thresholdSlider.setRange(0, 1, 0.001);
|
||||||
|
}
|
||||||
|
|
||||||
|
VolumeComponent::~VolumeComponent() {
|
||||||
|
audioProcessor.audioProducer.unregisterConsumer(consumer);
|
||||||
|
stopThread(1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VolumeComponent::paint(juce::Graphics& g) {
|
||||||
|
auto r = getLocalBounds().toFloat();
|
||||||
|
r.removeFromRight(r.getWidth() / 2);
|
||||||
|
|
||||||
|
g.setColour(juce::Colours::white);
|
||||||
|
g.fillRect(r);
|
||||||
|
|
||||||
|
auto channelHeight = r.getHeight();
|
||||||
|
auto leftVolumeHeight = channelHeight * leftVolume;
|
||||||
|
auto rightVolumeHeight = channelHeight * rightVolume;
|
||||||
|
|
||||||
|
auto leftRect = r.removeFromLeft(r.getWidth() / 2);
|
||||||
|
auto rightRect = r;
|
||||||
|
auto leftRegion = leftRect;
|
||||||
|
auto rightRegion = rightRect;
|
||||||
|
|
||||||
|
g.setGradientFill(juce::ColourGradient(juce::Colours::green, 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.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);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void VolumeComponent::timerCallback() {
|
||||||
|
repaint();
|
||||||
|
}
|
||||||
|
|
||||||
|
void VolumeComponent::run() {
|
||||||
|
audioProcessor.audioProducer.registerConsumer(consumer);
|
||||||
|
|
||||||
|
while (!threadShouldExit()) {
|
||||||
|
auto buffer = consumer->startProcessing();
|
||||||
|
|
||||||
|
float leftVolume = 0;
|
||||||
|
float rightVolume = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < buffer->size(); i += 2) {
|
||||||
|
leftVolume += buffer->at(i) * buffer->at(i);
|
||||||
|
rightVolume += buffer->at(i + 1) * buffer->at(i + 1);
|
||||||
|
}
|
||||||
|
// RMS
|
||||||
|
leftVolume = std::sqrt(leftVolume / (buffer->size() / 2));
|
||||||
|
rightVolume = std::sqrt(rightVolume / (buffer->size() / 2));
|
||||||
|
|
||||||
|
this->leftVolume = leftVolume;
|
||||||
|
this->rightVolume = rightVolume;
|
||||||
|
|
||||||
|
avgLeftVolume = (avgLeftVolume * 0.95) + (leftVolume * 0.05);
|
||||||
|
avgRightVolume = (avgRightVolume * 0.95) + (rightVolume * 0.05);
|
||||||
|
|
||||||
|
consumer->finishedProcessing();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void VolumeComponent::resized() {
|
||||||
|
auto r = getLocalBounds();
|
||||||
|
|
||||||
|
volumeSlider.setBounds(r.removeFromLeft(r.getWidth() / 2));
|
||||||
|
thresholdSlider.setBounds(r);
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <JuceHeader.h>
|
||||||
|
#include "../concurrency/BufferConsumer.h"
|
||||||
|
#include "../PluginProcessor.h"
|
||||||
|
|
||||||
|
class VolumeComponent : public juce::Component, public juce::Timer, public juce::Thread {
|
||||||
|
public:
|
||||||
|
VolumeComponent(OscirenderAudioProcessor& p);
|
||||||
|
~VolumeComponent() override;
|
||||||
|
|
||||||
|
void paint(juce::Graphics&) override;
|
||||||
|
void timerCallback() override;
|
||||||
|
void run() override;
|
||||||
|
void resized() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
OscirenderAudioProcessor& audioProcessor;
|
||||||
|
std::shared_ptr<BufferConsumer> consumer = std::make_shared<BufferConsumer>(1 << 11);
|
||||||
|
|
||||||
|
std::atomic<float> leftVolume = 0;
|
||||||
|
std::atomic<float> rightVolume = 0;
|
||||||
|
std::atomic<float> avgLeftVolume = 0;
|
||||||
|
std::atomic<float> avgRightVolume = 0;
|
||||||
|
|
||||||
|
juce::Slider volumeSlider;
|
||||||
|
juce::Slider thresholdSlider;
|
||||||
|
|
||||||
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(VolumeComponent)
|
||||||
|
};
|
|
@ -127,6 +127,10 @@
|
||||||
file="Source/components/VisualiserComponent.cpp"/>
|
file="Source/components/VisualiserComponent.cpp"/>
|
||||||
<FILE id="ZueyNl" name="VisualiserComponent.h" compile="0" resource="0"
|
<FILE id="ZueyNl" name="VisualiserComponent.h" compile="0" resource="0"
|
||||||
file="Source/components/VisualiserComponent.h"/>
|
file="Source/components/VisualiserComponent.h"/>
|
||||||
|
<FILE id="s8EVcE" name="VolumeComponent.cpp" compile="1" resource="0"
|
||||||
|
file="Source/components/VolumeComponent.cpp"/>
|
||||||
|
<FILE id="MWkfTv" name="VolumeComponent.h" compile="0" resource="0"
|
||||||
|
file="Source/components/VolumeComponent.h"/>
|
||||||
</GROUP>
|
</GROUP>
|
||||||
<GROUP id="{85A33213-D880-BD92-70D8-1901DA6D23F0}" name="audio">
|
<GROUP id="{85A33213-D880-BD92-70D8-1901DA6D23F0}" name="audio">
|
||||||
<FILE id="NWuowi" name="BitCrushEffect.cpp" compile="1" resource="0"
|
<FILE id="NWuowi" name="BitCrushEffect.cpp" compile="1" resource="0"
|
||||||
|
|
Ładowanie…
Reference in New Issue