From 1787bb601b74a8eab4108bc94439862ecbae9a1f Mon Sep 17 00:00:00 2001
From: reuk <reuk@users.noreply.github.com>
Date: Tue, 30 Nov 2021 21:11:56 +0000
Subject: [PATCH] WIP:  Testing project

---
 examples/CMake/AudioPlugin/CMakeLists.txt     |  4 +-
 examples/CMake/AudioPlugin/PluginEditor.cpp   | 65 ++++++++++++----
 examples/CMake/AudioPlugin/PluginEditor.h     | 25 +++++--
 .../CMake/AudioPlugin/PluginProcessor.cpp     | 74 +++++++------------
 examples/CMake/AudioPlugin/PluginProcessor.h  | 15 ++++
 examples/Plugins/AudioPluginDemo.h            | 18 +----
 6 files changed, 114 insertions(+), 87 deletions(-)

diff --git a/examples/CMake/AudioPlugin/CMakeLists.txt b/examples/CMake/AudioPlugin/CMakeLists.txt
index c808704ed..a3dc1dc90 100644
--- a/examples/CMake/AudioPlugin/CMakeLists.txt
+++ b/examples/CMake/AudioPlugin/CMakeLists.txt
@@ -42,14 +42,14 @@ juce_add_plugin(AudioPluginExample
     # ICON_BIG ...                              # ICON_* arguments specify a path to an image file to use as an icon for the Standalone
     # ICON_SMALL ...
     # COMPANY_NAME ...                          # Specify the name of the plugin's author
-    # IS_SYNTH TRUE/FALSE                       # Is this a synth or an effect?
+    IS_SYNTH FALSE                              # Is this a synth or an effect?
     # NEEDS_MIDI_INPUT TRUE/FALSE               # Does the plugin need midi input?
     # NEEDS_MIDI_OUTPUT TRUE/FALSE              # Does the plugin need midi output?
     # IS_MIDI_EFFECT TRUE/FALSE                 # Is this plugin a MIDI effect?
     # EDITOR_WANTS_KEYBOARD_FOCUS TRUE/FALSE    # Does the editor need keyboard focus?
     # COPY_PLUGIN_AFTER_BUILD TRUE/FALSE        # Should the plugin be installed to a default location after building?
     PLUGIN_MANUFACTURER_CODE Juce               # A four-character manufacturer id with at least one upper-case character
-    PLUGIN_CODE Dem0                            # A unique four-character plugin id with exactly one upper-case character
+    PLUGIN_CODE Dem1                            # A unique four-character plugin id with exactly one upper-case character
                                                 # GarageBand 10.3 requires the first letter to be upper-case, and the remaining letters to be lower-case
     FORMATS AU VST3 Standalone                  # The formats to build. Other valid formats are: AAX Unity VST AU AUv3
     PRODUCT_NAME "Audio Plugin Example")        # The name of the final executable, which can differ from the target name
diff --git a/examples/CMake/AudioPlugin/PluginEditor.cpp b/examples/CMake/AudioPlugin/PluginEditor.cpp
index 50f8eb44b..669b7bfa5 100644
--- a/examples/CMake/AudioPlugin/PluginEditor.cpp
+++ b/examples/CMake/AudioPlugin/PluginEditor.cpp
@@ -5,29 +5,64 @@
 AudioPluginAudioProcessorEditor::AudioPluginAudioProcessorEditor (AudioPluginAudioProcessor& p)
     : AudioProcessorEditor (&p), processorRef (p)
 {
-    juce::ignoreUnused (processorRef);
-    // Make sure that before the constructor has finished, you've set the
-    // editor's size to whatever you need it to be.
-    setSize (400, 300);
-}
+    setSize (800, 200);
 
-AudioPluginAudioProcessorEditor::~AudioPluginAudioProcessorEditor()
-{
+    addAndMakeVisible (button);
+    addAndMakeVisible (label);
+
+    updateText();
+
+    label.setJustificationType (juce::Justification::centred);
+    button.onClick = [this] { processorRef.useNextChannel(); };
+
+    startTimerHz (60);
 }
 
-//==============================================================================
 void AudioPluginAudioProcessorEditor::paint (juce::Graphics& g)
 {
-    // (Our component is opaque, so we must completely fill the background with a solid colour)
-    g.fillAll (getLookAndFeel().findColour (juce::ResizableWindow::backgroundColourId));
+    g.fillAll (juce::Colours::black);
+
+    juce::FlexBox box;
+
+    for (auto& i : processorRef.inputLevels)
+    {
+        juce::ignoreUnused (i);
+        box.items.add (juce::FlexItem().withFlex (1.0f).withMargin (4.0f));
+    }
 
-    g.setColour (juce::Colours::white);
-    g.setFont (15.0f);
-    g.drawFittedText ("Hello World!", getLocalBounds(), juce::Justification::centred, 1);
+    box.performLayout (getLocalBounds().removeFromTop (getLocalBounds().proportionOfHeight (0.5f)));
+
+    for (auto i = 0; i < (int) processorRef.inputLevels.size(); ++i)
+    {
+        const auto minDb = -50.0f;
+        const auto db = juce::Decibels::gainToDecibels (processorRef.inputLevels[(size_t) i].load(), minDb);
+        const auto scaledDb = juce::jmap (db, minDb, 12.0f, 0.0f, 1.0f);
+        const auto fullBox = box.items[i].currentBounds;
+        const auto textHeight = 20.0f;
+
+        g.setColour (juce::Colours::cyan);
+        g.fillRect (fullBox.withHeight (scaledDb * (fullBox.getHeight() - textHeight)).withBottomY (fullBox.getBottom()));
+
+        const auto channelType = getTypeOfAbsoluteChannel (true, i);
+
+        g.setColour (juce::Colours::white);
+        g.drawText (juce::AudioChannelSet::getAbbreviatedChannelTypeName (channelType),
+                    fullBox.withHeight (textHeight),
+                    juce::Justification::centred);
+    }
 }
 
 void AudioPluginAudioProcessorEditor::resized()
 {
-    // This is generally where you'll want to lay out the positions of any
-    // subcomponents in your editor..
+    auto b = getLocalBounds();
+    b.removeFromTop (b.proportionOfHeight (0.5f));
+    button.setBounds (b.removeFromTop (b.proportionOfHeight (0.5f)).withSizeKeepingCentre (200, 24));
+    label.setBounds (b);
 }
+
+void AudioPluginAudioProcessorEditor::updateText()
+{
+    label.setText (juce::AudioChannelSet::getChannelTypeName (getTypeOfAbsoluteChannel (false, processorRef.getChannel())), juce::dontSendNotification);
+}
+
+void AudioPluginAudioProcessorEditor::timerCallback() { repaint(); }
diff --git a/examples/CMake/AudioPlugin/PluginEditor.h b/examples/CMake/AudioPlugin/PluginEditor.h
index ef96e04a3..bd874a8a3 100644
--- a/examples/CMake/AudioPlugin/PluginEditor.h
+++ b/examples/CMake/AudioPlugin/PluginEditor.h
@@ -3,20 +3,31 @@
 #include "PluginProcessor.h"
 
 //==============================================================================
-class AudioPluginAudioProcessorEditor  : public juce::AudioProcessorEditor
+class AudioPluginAudioProcessorEditor  : public juce::AudioProcessorEditor,
+                                         private juce::Timer
 {
 public:
     explicit AudioPluginAudioProcessorEditor (AudioPluginAudioProcessor&);
-    ~AudioPluginAudioProcessorEditor() override;
 
-    //==============================================================================
-    void paint (juce::Graphics&) override;
     void resized() override;
+    void paint (juce::Graphics& g) override;
 
 private:
-    // This reference is provided as a quick way for your editor to
-    // access the processor object that created it.
+    auto getTypeOfAbsoluteChannel (bool isInput, int index) const
+    {
+        int busIndex = 0;
+        const auto channelIndex = processorRef.getOffsetInBusBufferForAbsoluteChannelIndex (isInput, index, busIndex);
+        const auto channelLayout = processorRef.getChannelLayoutOfBus (isInput, busIndex);
+        return channelLayout.getTypeOfChannel (channelIndex);
+    }
+
+    void updateText();
+    void timerCallback() override;
+
     AudioPluginAudioProcessor& processorRef;
 
-    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioPluginAudioProcessorEditor)
+    juce::TextButton button { "next channel" };
+    juce::Label label;
+
+    juce::ScopedValueSetter<std::function<void()>> scope { processorRef.channelChanged, [this] { updateText(); } };
 };
diff --git a/examples/CMake/AudioPlugin/PluginProcessor.cpp b/examples/CMake/AudioPlugin/PluginProcessor.cpp
index 0dd5ac2a1..f1aaefe2c 100644
--- a/examples/CMake/AudioPlugin/PluginProcessor.cpp
+++ b/examples/CMake/AudioPlugin/PluginProcessor.cpp
@@ -1,16 +1,13 @@
 #include "PluginProcessor.h"
 #include "PluginEditor.h"
 
+#include <thread>
+
 //==============================================================================
 AudioPluginAudioProcessor::AudioPluginAudioProcessor()
      : AudioProcessor (BusesProperties()
-                     #if ! JucePlugin_IsMidiEffect
-                      #if ! JucePlugin_IsSynth
-                       .withInput  ("Input",  juce::AudioChannelSet::stereo(), true)
-                      #endif
-                       .withOutput ("Output", juce::AudioChannelSet::stereo(), true)
-                     #endif
-                       )
+                       .withInput  ("Input",  juce::AudioChannelSet::create7point1point4(), true)
+                       .withOutput ("Output", juce::AudioChannelSet::create7point1point4(), true))
 {
 }
 
@@ -87,8 +84,11 @@ void AudioPluginAudioProcessor::changeProgramName (int index, const juce::String
 void AudioPluginAudioProcessor::prepareToPlay (double sampleRate, int samplesPerBlock)
 {
     // Use this method as the place to do any pre-playback
-    // initialisation that you need..
+    // initialisation that you need
     juce::ignoreUnused (sampleRate, samplesPerBlock);
+
+    inputLevels = std::vector<std::atomic<float>> ((size_t) getTotalNumInputChannels());
+    std::fill (inputLevels.begin(), inputLevels.end(), 0.0f);
 }
 
 void AudioPluginAudioProcessor::releaseResources()
@@ -97,60 +97,38 @@ void AudioPluginAudioProcessor::releaseResources()
     // spare memory, etc.
 }
 
-bool AudioPluginAudioProcessor::isBusesLayoutSupported (const BusesLayout& layouts) const
+bool AudioPluginAudioProcessor::isBusesLayoutSupported (const BusesLayout& layout) const
 {
   #if JucePlugin_IsMidiEffect
     juce::ignoreUnused (layouts);
     return true;
   #else
-    // This is the place where you check if the layout is supported.
-    // In this template code we only support mono or stereo.
-    // Some plugin hosts, such as certain GarageBand versions, will only
-    // load plugins that support stereo bus layouts.
-    if (layouts.getMainOutputChannelSet() != juce::AudioChannelSet::mono()
-     && layouts.getMainOutputChannelSet() != juce::AudioChannelSet::stereo())
-        return false;
-
-    // This checks if the input layout matches the output layout
-   #if ! JucePlugin_IsSynth
-    if (layouts.getMainOutputChannelSet() != layouts.getMainInputChannelSet())
-        return false;
-   #endif
-
-    return true;
+    return layout == BusesLayout { { juce::AudioChannelSet::create7point1point4() },
+                                   { juce::AudioChannelSet::create7point1point4() } };
   #endif
 }
 
 void AudioPluginAudioProcessor::processBlock (juce::AudioBuffer<float>& buffer,
-                                              juce::MidiBuffer& midiMessages)
+                                              juce::MidiBuffer&)
 {
-    juce::ignoreUnused (midiMessages);
-
     juce::ScopedNoDenormals noDenormals;
-    auto totalNumInputChannels  = getTotalNumInputChannels();
-    auto totalNumOutputChannels = getTotalNumOutputChannels();
-
-    // In case we have more outputs than inputs, this code clears any output
-    // channels that didn't contain input data, (because these aren't
-    // guaranteed to be empty - they may contain garbage).
-    // This is here to avoid people getting screaming feedback
-    // when they first compile a plugin, but obviously you don't need to keep
-    // this code if your algorithm always overwrites all the output channels.
-    for (auto i = totalNumInputChannels; i < totalNumOutputChannels; ++i)
-        buffer.clear (i, 0, buffer.getNumSamples());
 
-    // This is the place where you'd normally do the guts of your plugin's
-    // audio processing...
-    // Make sure to reset the state if your inner loop is processing
-    // the samples and the outer loop is handling the channels.
-    // Alternatively, you can process the samples with the channels
-    // interleaved by keeping the same state.
-    for (int channel = 0; channel < totalNumInputChannels; ++channel)
+    const auto totalNumInputChannels = getTotalNumInputChannels();
+
+    for (auto i = 0; i < totalNumInputChannels; ++i)
     {
-        auto* channelData = buffer.getWritePointer (channel);
-        juce::ignoreUnused (channelData);
-        // ..do something to the data...
+        auto& storedLevel = inputLevels[(size_t) i];
+        const auto mag = buffer.getMagnitude (i, 0, buffer.getNumSamples());
+        storedLevel = std::max (storedLevel * 0.95f, mag);
     }
+
+    const auto totalNumOutputChannels = getTotalNumOutputChannels();
+
+    for (auto i = 0; i < totalNumOutputChannels; ++i)
+        buffer.clear (i, 0, buffer.getNumSamples());
+
+    auto* ptr = buffer.getWritePointer (channel);
+    std::for_each (ptr, ptr + buffer.getNumSamples(), [this] (auto& c) { c = random.nextFloat() * 0.1f; });
 }
 
 //==============================================================================
diff --git a/examples/CMake/AudioPlugin/PluginProcessor.h b/examples/CMake/AudioPlugin/PluginProcessor.h
index 61413bb18..b07d7b5fd 100644
--- a/examples/CMake/AudioPlugin/PluginProcessor.h
+++ b/examples/CMake/AudioPlugin/PluginProcessor.h
@@ -42,7 +42,22 @@ public:
     void getStateInformation (juce::MemoryBlock& destData) override;
     void setStateInformation (const void* data, int sizeInBytes) override;
 
+    void useNextChannel()
+    {
+        channel = (channel + 1) % getTotalNumOutputChannels();
+        channelChanged();
+    }
+
+    int getChannel() const { return channel; }
+
+    std::function<void()> channelChanged;
+
+    std::vector<std::atomic<float>> inputLevels;
+
 private:
+    std::atomic<int> channel { 0 };
+    juce::Random random;
+
     //==============================================================================
     JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioPluginAudioProcessor)
 };
diff --git a/examples/Plugins/AudioPluginDemo.h b/examples/Plugins/AudioPluginDemo.h
index f4acc5236..5fa407693 100644
--- a/examples/Plugins/AudioPluginDemo.h
+++ b/examples/Plugins/AudioPluginDemo.h
@@ -194,20 +194,8 @@ public:
     ~JuceDemoPluginAudioProcessor() override = default;
 
     //==============================================================================
-    bool isBusesLayoutSupported (const BusesLayout& layouts) const override
+    bool isBusesLayoutSupported (const BusesLayout&) const override
     {
-        // Only mono/stereo and input/output must have same layout
-        const auto& mainOutput = layouts.getMainOutputChannelSet();
-        const auto& mainInput  = layouts.getMainInputChannelSet();
-
-        // input and output layout must either be the same or the input must be disabled altogether
-        if (! mainInput.isDisabled() && mainInput != mainOutput)
-            return false;
-
-        // only allow stereo and mono
-        if (mainOutput.size() > 2)
-            return false;
-
         return true;
     }
 
@@ -665,8 +653,8 @@ private:
 
     static BusesProperties getBusesProperties()
     {
-        return BusesProperties().withInput  ("Input",  AudioChannelSet::stereo(), true)
-                                .withOutput ("Output", AudioChannelSet::stereo(), true);
+        return BusesProperties().withInput  ("Input",  AudioChannelSet::create7point1point4(), true)
+                                .withOutput ("Output", AudioChannelSet::create7point1point4(), true);
     }
 
     JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (JuceDemoPluginAudioProcessor)
-- 
2.30.1 (Apple Git-130)

