dev/juce/ TapSamplerGitDiff


From github

Diff 0: 0268fe68eb3bfe0084e9fe7168195d64f8acb3d3 to f960ba20b9a81d2a8615d60b1e1425b9ef94edcc

index 723fd44..f132eed 100644 — a/Source/[PluginEditor](PluginEditor).cpp
+++ b/Source/PluginEditor.cpp
@@ -28,15 +28,49 @@ HelloSamplerAudioProcessorEditor::~HelloSamplerAudioProcessorEditor()
 //==============================================================================
 void HelloSamplerAudioProcessorEditor::paint (Graphics& g)
 {
-    // (Our component is opaque, so we must completely fill the background with a solid colour)
-    g.fillAll (getLookAndFeel().findColour (ResizableWindow::backgroundColourId));
-
+    g.fillAll (Colours::black);
+    
     g.setColour (Colours::white);
     g.setFont (15.0f);
-    g.drawFittedText ("Hello World!", getLocalBounds(), Justification::centred, 1);
+    
+    if (processor.getNumSamplerSounds() > 0)
+    {
+        g.fillAll (Colours::red);
+        g.drawText ("Sound Loaded", getWidth() / 2 - 50, getHeight() / 2 - 10, 100, 20, Justification::centred);
+    }
+    else
+    {
+        g.drawText ("Load a Sound", getWidth() / 2 - 50, getHeight() / 2 - 10, 100, 20, Justification::centred);
+    }
 }

 void HelloSamplerAudioProcessorEditor::resized()
 {
-    mLoadButton.setBounds (getWidth() / 2 - 50, getHeight() / 2 - 50, 100, 100);
+    //mLoadButton.setBounds (getWidth() / 2 - 50, getHeight() / 2 - 50, 100, 100);
+}
+
+bool HelloSamplerAudioProcessorEditor::isInterestedInFileDrag (const StringArray& files)
+{
+    for (auto file : files)
+    {
+        if (file.contains (".wav") || file.contains (".mp3") || file.contains (".aif"))
+        {
+            return true;
+        }
+    }
+    
+    return false;
+}
+
+void HelloSamplerAudioProcessorEditor::filesDropped (const StringArray& files, int x, int y)
+{
+    for (auto file : files)
+    {
+        if (isInterestedInFileDrag (file))
+        {
+            processor.loadFile (file);
+        }
+    }
+    
+    repaint();
 }
diff –git a/Source/[PluginEditor](PluginEditor).h b/Source/[PluginEditor](PluginEditor).h index 6977b1a..9f76bcf 100644
--- a/Source/PluginEditor.h
+++ b/Source/PluginEditor.h
@@ -16,7 +16,8 @@
 //==============================================================================
 /**
 */
-class HelloSamplerAudioProcessorEditor  : public AudioProcessorEditor
+class HelloSamplerAudioProcessorEditor  : public AudioProcessorEditor,
+                                          public FileDragAndDropTarget
 {
 public:
     HelloSamplerAudioProcessorEditor (HelloSamplerAudioProcessor&);
@@ -25,6 +26,9 @@ public:
     //==============================================================================
     void paint (Graphics&) override;
     void resized() override;
+    
+    bool isInterestedInFileDrag (const StringArray& files) override;
+    void filesDropped (const StringArray& files, int x, int y) override;

 private:
     TextButton mLoadButton { "Load" };
diff –git a/Source/[PluginProcessor](PluginProcessor).cpp b/Source/[PluginProcessor](PluginProcessor).cpp index bf74960..1edaab0 100644
--- a/Source/PluginProcessor.cpp
+++ b/Source/PluginProcessor.cpp
@@ -174,6 +174,8 @@ void HelloSamplerAudioProcessor::setStateInformation (const void* data, int size

 void HelloSamplerAudioProcessor::loadFile()
 {
+    mSampler.clearSounds();
+    
     FileChooser chooser { "Please load a file" };

     if (chooser.browseForFileToOpen())
@@ -188,6 +190,19 @@ void HelloSamplerAudioProcessor::loadFile()
     mSampler.addSound (new SamplerSound ("Sample", *mFormatReader, range, 60, 0.1, 0.1, 10.0));
 }

+void HelloSamplerAudioProcessor::loadFile (const String& path)
+{
+    mSampler.clearSounds();
+    
+    auto file = File (path);
+    mFormatReader = mFormatManager.createReaderFor (file);
+    
+    BigInteger range;
+    range.setRange (0, 128, true);
+    
+    mSampler.addSound (new SamplerSound ("Sample", *mFormatReader, range, 60, 0.1, 0.1, 10.0));
+}
+
 //==============================================================================
 // This creates new instances of the plugin..
 AudioProcessor* JUCE_CALLTYPE createPluginFilter()
diff –git a/Source/[PluginProcessor](PluginProcessor).h b/Source/[PluginProcessor](PluginProcessor).h index b7dbe43..b16ab4c 100644
--- a/Source/PluginProcessor.h
+++ b/Source/PluginProcessor.h
@@ -56,6 +56,9 @@ public:
     void setStateInformation (const void* data, int sizeInBytes) override;

     void loadFile();
+    void loadFile (const String& path);
+    
+    int getNumSamplerSounds() { return mSampler.getNumSounds(); }

 private:
     Synthesiser mSampler;

Diff 0: f960ba20b9a81d2a8615d60b1e1425b9ef94edcc to f61194d0081a7399c45f3778d267bfabfff8958b

index f132eed..a8ac4ce 100644 — a/Source/[PluginEditor](PluginEditor).cpp
+++ b/Source/PluginEditor.cpp
@@ -18,7 +18,7 @@ HelloSamplerAudioProcessorEditor::HelloSamplerAudioProcessorEditor (HelloSampler
     mLoadButton.onClick = [&]() { processor.loadFile(); };
     addAndMakeVisible (mLoadButton);

-    setSize (200, 200);
+    setSize (600, 200);
 }

 HelloSamplerAudioProcessorEditor::~HelloSamplerAudioProcessorEditor()
@@ -29,19 +29,50 @@ HelloSamplerAudioProcessorEditor::~HelloSamplerAudioProcessorEditor()
 void HelloSamplerAudioProcessorEditor::paint (Graphics& g)
 {
     g.fillAll (Colours::black);
-    
     g.setColour (Colours::white);
-    g.setFont (15.0f);

-    if (processor.getNumSamplerSounds() > 0)
-    {
-        g.fillAll (Colours::red);
-        g.drawText ("Sound Loaded", getWidth() / 2 - 50, getHeight() / 2 - 10, 100, 20, Justification::centred);
-    }
-    else
+    if (mShouldBePainting)
     {
-        g.drawText ("Load a Sound", getWidth() / 2 - 50, getHeight() / 2 - 10, 100, 20, Justification::centred);
+        Path p;
+        mAudioPoints.clear();
+        
+        auto waveform = processor.getWaveForm();
+        auto ratio = waveform.getNumSamples() / getWidth();
+        auto buffer = waveform.getReadPointer (0);
+    
+        //scale audio file to window on x axis
+        for (int sample = 0; sample < waveform.getNumSamples(); sample+=ratio)
+        {
+            mAudioPoints.push_back (buffer[sample]);
+        }
+    
+        p.startNewSubPath (0, getHeight() / 2);
+    
+        //scale on y axis
+        for (int sample = 0; sample < mAudioPoints.size(); ++sample)
+        {
+            auto point = jmap<float> (mAudioPoints[sample], -1.0f, 1.0f, 200, 0);
+            p.lineTo (sample, point);
+        }
+    
+        g.strokePath(p, PathStrokeType (2));
+    
+        mShouldBePainting = false;
     }
+    
+    
+//    g.setColour (Colours::white);
+//    g.setFont (15.0f);
+//
+//    if (processor.getNumSamplerSounds() > 0)
+//    {
+//        g.fillAll (Colours::red);
+//        g.drawText ("Sound Loaded", getWidth() / 2 - 50, getHeight() / 2 - 10, 100, 20, Justification::centred);
+//    }
+//    else
+//    {
+//        g.drawText ("Load a Sound", getWidth() / 2 - 50, getHeight() / 2 - 10, 100, 20, Justification::centred);
+//    }
 }

 void HelloSamplerAudioProcessorEditor::resized()
@@ -68,6 +99,7 @@ void HelloSamplerAudioProcessorEditor::filesDropped (const StringArray& files, i
     {
         if (isInterestedInFileDrag (file))
         {
+            mShouldBePainting = true;
             processor.loadFile (file);
         }
     }
diff –git a/Source/[PluginEditor](PluginEditor).h b/Source/[PluginEditor](PluginEditor).h index 9f76bcf..e28d869 100644
--- a/Source/PluginEditor.h
+++ b/Source/PluginEditor.h
@@ -32,6 +32,8 @@ public:

 private:
     TextButton mLoadButton { "Load" };
+    std::vector<float> mAudioPoints;
+    bool mShouldBePainting { false };

     HelloSamplerAudioProcessor& processor;
diff –git a/Source/[PluginProcessor](PluginProcessor).cpp b/Source/[PluginProcessor](PluginProcessor).cpp index 1edaab0..bf97e42 100644
--- a/Source/PluginProcessor.cpp
+++ b/Source/PluginProcessor.cpp
@@ -197,6 +197,11 @@ void HelloSamplerAudioProcessor::loadFile (const String& path)
     auto file = File (path);
     mFormatReader = mFormatManager.createReaderFor (file);

+    auto sampleLength = static_cast<int>(mFormatReader->lengthInSamples);
+    
+    mWaveForm.setSize (1, sampleLength);
+    mFormatReader->read (&mWaveForm, 0, sampleLength, 0, true, false);
+        
     BigInteger range;
     range.setRange (0, 128, true);
diff –git a/Source/[PluginProcessor](PluginProcessor).h b/Source/[PluginProcessor](PluginProcessor).h index b16ab4c..c8ef3b8 100644
--- a/Source/PluginProcessor.h
+++ b/Source/PluginProcessor.h
@@ -59,10 +59,12 @@ public:
     void loadFile (const String& path);

     int getNumSamplerSounds() { return mSampler.getNumSounds(); }
+    AudioBuffer<float>& getWaveForm() { return mWaveForm; }

 private:
     Synthesiser mSampler;
     const int mNumVoices { 3 };
+    AudioBuffer<float> mWaveForm;

     AudioFormatManager mFormatManager;
     AudioFormatReader* mFormatReader { nullptr };

Diff 0: f61194d0081a7399c45f3778d267bfabfff8958b to 7d6d192f9a547bb35df07edadc9ea9ffb888429d

new file mode 100644 index 0000000..6a7eb89
--- /dev/null
+++ b/Source/ADSRComponent.cpp
@@ -0,0 +1,90 @@
+/*
+  ==============================================================================
+
+    ADSRComponent.cpp
+    Created: 14 Mar 2020 2:52:49pm
+    Author:  Joshua Hodge
+
+  ==============================================================================
+*/
+
+#include <JuceHeader.h>
+#include "ADSRComponent.h"
+
+//==============================================================================
+ADSRComponent::ADSRComponent (HelloSamplerAudioProcessor& p) : processor (p)
+{
+    mAttackSlider.setRange (0.1f, 2.0f, 0.01f);
+    mAttackSlider.setValue (0.1f);
+    mAttackSlider.setSliderStyle (Slider::SliderStyle::RotaryVerticalDrag);
+    mAttackSlider.setTextBoxStyle (Slider::TextBoxBelow, true, 35, 20);
+    addAndMakeVisible (mAttackSlider);
+    mAttackSlider.addListener (this);
+    
+    mDecaySlider.setRange (0.1f, 1.0f, 0.01f);
+    mDecaySlider.setValue (0.1f);
+    mDecaySlider.setSliderStyle (Slider::SliderStyle::RotaryVerticalDrag);
+    mDecaySlider.setTextBoxStyle (Slider::TextBoxBelow, true, 35, 20);
+    addAndMakeVisible (mDecaySlider);
+    mDecaySlider.addListener (this);
+    
+    mSustainSlider.setRange (0.1f, 1.0f, 0.01f);
+    mSustainSlider.setValue (1.0f);
+    mSustainSlider.setSliderStyle (Slider::SliderStyle::RotaryVerticalDrag);
+    mSustainSlider.setTextBoxStyle (Slider::TextBoxBelow, true, 35, 20);
+    addAndMakeVisible (mSustainSlider);
+    mSustainSlider.addListener (this);
+    
+    mReleaseSlider.setRange (0.1f, 5.0f, 0.01f);
+    mReleaseSlider.setValue (0.4f);
+    mReleaseSlider.setSliderStyle (Slider::SliderStyle::RotaryVerticalDrag);
+    mReleaseSlider.setTextBoxStyle (Slider::TextBoxBelow, true, 35, 20);
+    addAndMakeVisible (mReleaseSlider);
+    mReleaseSlider.addListener (this);
+    
+    setSize (400, 200);
+}
+
+ADSRComponent::~ADSRComponent()
+{
+}
+
+void ADSRComponent::paint (Graphics& g)
+{
+    g.fillAll (Colours::orangered);
+}
+
+void ADSRComponent::resized()
+{
+    const auto dialSizeX = 0.25f;
+    const auto dialSizeY = 0.6f;
+    const auto yPosition = 0.2f;
+    
+    mAttackSlider.setBoundsRelative (0.0f, yPosition, dialSizeX, dialSizeY);
+    mDecaySlider.setBoundsRelative (0.25f, yPosition, dialSizeX, dialSizeY);
+    mSustainSlider.setBoundsRelative (0.5f, yPosition, dialSizeX, dialSizeY);
+    mReleaseSlider.setBoundsRelative (0.75f, yPosition, dialSizeX, dialSizeY);
+}
+
+void ADSRComponent::sliderValueChanged (Slider *slider)
+{
+    if (slider == &mAttackSlider)
+    {
+        processor.setADSRAttack (mAttackSlider.getValue());
+    }
+    
+    if (slider == &mDecaySlider)
+    {
+        processor.setADSRDecay (mDecaySlider.getValue());
+    }
+    
+    if (slider == &mSustainSlider)
+    {
+        processor.setADSRSustain (mSustainSlider.getValue());
+    }
+    
+    if (slider == &mReleaseSlider)
+    {
+        processor.setADSRRelease (mReleaseSlider.getValue());
+    }
+}
diff –git a/Source/[ADSRComponent](ADSRComponent).h b/Source/[ADSRComponent](ADSRComponent).h new file mode 100644
index 0000000..66ea725
--- /dev/null
+++ b/Source/ADSRComponent.h
@@ -0,0 +1,45 @@
+/*
+  ==============================================================================
+
+    ADSRComponent.h
+    Created: 14 Mar 2020 2:52:49pm
+    Author:  Joshua Hodge
+
+  ==============================================================================
+*/
+
+#pragma once
+
+#include <JuceHeader.h>
+#include "PluginProcessor.h"
+
+//==============================================================================
+/*
+*/
+class ADSRComponent : public Component,
+                      public Slider::Listener
+{
+public:
+    ADSRComponent (HelloSamplerAudioProcessor& p);
+    ~ADSRComponent();
+
+    void paint (Graphics&) override;
+    void resized() override;
+    
+    void sliderValueChanged (Slider *slider) override;
+    
+    Slider& getAttackSlider() { return mAttackSlider; }
+    Slider& getDecaySlider() { return mDecaySlider; }
+    Slider& getSustainSlider() { return mSustainSlider; }
+    Slider& getReleaseSlider() { return mReleaseSlider; }
+
+private:
+    Slider mAttackSlider;
+    Slider mDecaySlider;
+    Slider mSustainSlider;
+    Slider mReleaseSlider;
+    
+    HelloSamplerAudioProcessor& processor;
+        
+    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ADSRComponent)
+};
diff –git a/Source/[MySampler](MySampler).cpp b/Source/[MySampler](MySampler).cpp new file mode 100644
index 0000000..edc6018
--- /dev/null
+++ b/Source/MySampler.cpp
@@ -0,0 +1,11 @@
+/*
+  ==============================================================================
+
+    MySampler.cpp
+    Created: 14 Mar 2020 1:41:28pm
+    Author:  Joshua Hodge
+
+  ==============================================================================
+*/
+
+#include "MySampler.h"
diff –git a/Source/[MySampler](MySampler).h b/Source/[MySampler](MySampler).h new file mode 100644
index 0000000..adb1b93
--- /dev/null
+++ b/Source/MySampler.h
@@ -0,0 +1,55 @@
+/*
+  ==============================================================================
+
+    MySampler.h
+    Created: 14 Mar 2020 1:41:28pm
+    Author:  Joshua Hodge
+
+  ==============================================================================
+*/
+
+#pragma once
+#include <JuceHeader.h>
+
+class MySampler : public Synthesiser
+{
+public:
+    void handleMidiEvent (const MidiMessage &m) override
+    {
+        const int channel = m.getChannel();
+        
+        if (m.isNoteOn())
+        {
+            noteOn (channel, m.getNoteNumber(), m.getFloatVelocity());
+            mADSR.noteOn();
+        }
+        else if (m.isNoteOff())
+        {
+            noteOff (channel, m.getNoteNumber(), m.getFloatVelocity(), true);
+            mADSR.noteOff();
+        }
+    }
+
+    //public methods
+    
+    void prepareToPlay (int sampleRate)
+    {
+        setCurrentPlaybackSampleRate (sampleRate);
+        mADSR.setSampleRate (sampleRate);
+        mADSR.setParameters (mADSRParams);
+    }
+    
+    void getNextAudioBlock (AudioBuffer<float>& buffer, const MidiBuffer& midiMessages, int startSample, int numSamples)
+    {
+        renderNextBlock (buffer, midiMessages, startSample, numSamples);
+        mADSR.applyEnvelopeToBuffer (buffer, startSample, numSamples);
+    }
+    
+    //Access methods
+    ADSR& getADSR() { return mADSR; }
+    ADSR::Parameters& getADSRParams() { return mADSRParams; }
+    
+private:
+    ADSR mADSR;
+    ADSR::Parameters mADSRParams;
+};
diff –git a/Source/[PluginEditor](PluginEditor).cpp b/Source/[PluginEditor](PluginEditor).cpp index a8ac4ce..f726008 100644
--- a/Source/PluginEditor.cpp
+++ b/Source/PluginEditor.cpp
@@ -18,6 +18,54 @@ HelloSamplerAudioProcessorEditor::HelloSamplerAudioProcessorEditor (HelloSampler
     mLoadButton.onClick = [&]() { processor.loadFile(); };
     addAndMakeVisible (mLoadButton);

+    //Attack Slider
+    mAttackSlider.setSliderStyle (Slider::SliderStyle::RotaryVerticalDrag);
+    mAttackSlider.setTextBoxStyle (Slider::TextBoxBelow, true, 40, 20);
+    mAttackSlider.setColour (Slider::ColourIds::thumbColourId, Colours::red);
+    mAttackSlider.setRange (0.0f, 5.0f, 0.01f);
+    addAndMakeVisible (mAttackSlider);
+    
+    mAttackLabel.setFont (10.0f);
+    mAttackLabel.setText ("Attack", NotificationType::dontSendNotification);
+    mAttackLabel.setJustificationType (Justification::centredTop);
+    mAttackLabel.attachToComponent (&mAttackSlider, false);
+    
+    //Decay Slider
+    mDecaySlider.setSliderStyle (Slider::SliderStyle::RotaryVerticalDrag);
+    mDecaySlider.setTextBoxStyle (Slider::TextBoxBelow, true, 40, 20);
+    mDecaySlider.setColour (Slider::ColourIds::thumbColourId, Colours::red);
+    mDecaySlider.setRange (0.0f, 5.0f, 0.01f);
+    addAndMakeVisible (mDecaySlider);
+    
+    mDecayLabel.setFont (10.0f);
+    mDecayLabel.setText ("Decay", NotificationType::dontSendNotification);
+    mDecayLabel.setJustificationType (Justification::centredTop);
+    mDecayLabel.attachToComponent (&mDecaySlider, false);
+    
+    //Sustain Slider
+    mSustainSlider.setSliderStyle (Slider::SliderStyle::RotaryVerticalDrag);
+    mSustainSlider.setTextBoxStyle (Slider::TextBoxBelow, true, 40, 20);
+    mSustainSlider.setColour (Slider::ColourIds::thumbColourId, Colours::red);
+    mSustainSlider.setRange (0.0f, 1.0f, 0.01f);
+    addAndMakeVisible (mSustainSlider);
+    
+    mSustainLabel.setFont (10.0f);
+    mSustainLabel.setText ("Sustain", NotificationType::dontSendNotification);
+    mSustainLabel.setJustificationType (Justification::centredTop);
+    mSustainLabel.attachToComponent (&mSustainSlider, false);
+    
+    //Release Slider
+    mReleaseSlider.setSliderStyle (Slider::SliderStyle::RotaryVerticalDrag);
+    mReleaseSlider.setTextBoxStyle (Slider::TextBoxBelow, true, 40, 20);
+    mReleaseSlider.setColour (Slider::ColourIds::thumbColourId, Colours::red);
+    mReleaseSlider.setRange (0.0f, 5.0f, 0.01f);
+    addAndMakeVisible (mReleaseSlider);
+    
+    mReleaseLabel.setFont (10.0f);
+    mReleaseLabel.setText ("Release", NotificationType::dontSendNotification);
+    mReleaseLabel.setJustificationType (Justification::centredTop);
+    mReleaseLabel.attachToComponent (&mReleaseSlider, false);
+    
     setSize (600, 200);
 }

@@ -78,6 +126,16 @@ void HelloSamplerAudioProcessorEditor::paint (Graphics& g)
 void HelloSamplerAudioProcessorEditor::resized()
 {
     //mLoadButton.setBounds (getWidth() / 2 - 50, getHeight() / 2 - 50, 100, 100);
+    
+    const auto startX = 0.6f;
+    const auto startY = 0.6f;
+    const auto dialWidth = 0.1f;
+    const auto dialHeight = 0.4f;
+    
+    mAttackSlider.setBoundsRelative (startX, startY, dialWidth, dialHeight);
+    mDecaySlider.setBoundsRelative (startX + dialWidth, startY, dialWidth, dialHeight);
+    mSustainSlider.setBoundsRelative (startX + (dialWidth * 2), startY, dialWidth, dialHeight);
+    mReleaseSlider.setBoundsRelative (startX + (dialWidth * 3), startY, dialWidth, dialHeight);
 }

 bool HelloSamplerAudioProcessorEditor::isInterestedInFileDrag (const StringArray& files)
diff –git a/Source/[PluginEditor](PluginEditor).h b/Source/[PluginEditor](PluginEditor).h index e28d869..98630cc 100644
--- a/Source/PluginEditor.h
+++ b/Source/PluginEditor.h
@@ -35,6 +35,9 @@ private:
     std::vector<float> mAudioPoints;
     bool mShouldBePainting { false };

+    Slider mAttackSlider, mDecaySlider, mSustainSlider, mReleaseSlider;
+    Label mAttackLabel, mDecayLabel, mSustainLabel, mReleaseLabel;
+    
     HelloSamplerAudioProcessor& processor;

     JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (HelloSamplerAudioProcessorEditor)

Diff 0: 7d6d192f9a547bb35df07edadc9ea9ffb888429d to dacfb9c75d4288e4f199df9f33682945c6b59c12

index f726008..892971d 100644 — a/Source/[PluginEditor](PluginEditor).cpp
+++ b/Source/PluginEditor.cpp
@@ -23,6 +23,7 @@ HelloSamplerAudioProcessorEditor::HelloSamplerAudioProcessorEditor (HelloSampler
     mAttackSlider.setTextBoxStyle (Slider::TextBoxBelow, true, 40, 20);
     mAttackSlider.setColour (Slider::ColourIds::thumbColourId, Colours::red);
     mAttackSlider.setRange (0.0f, 5.0f, 0.01f);
+    mAttackSlider.addListener (this);
     addAndMakeVisible (mAttackSlider);

     mAttackLabel.setFont (10.0f);
@@ -35,6 +36,7 @@ HelloSamplerAudioProcessorEditor::HelloSamplerAudioProcessorEditor (HelloSampler
     mDecaySlider.setTextBoxStyle (Slider::TextBoxBelow, true, 40, 20);
     mDecaySlider.setColour (Slider::ColourIds::thumbColourId, Colours::red);
     mDecaySlider.setRange (0.0f, 5.0f, 0.01f);
+    mDecaySlider.addListener (this);
     addAndMakeVisible (mDecaySlider);

     mDecayLabel.setFont (10.0f);
@@ -47,6 +49,7 @@ HelloSamplerAudioProcessorEditor::HelloSamplerAudioProcessorEditor (HelloSampler
     mSustainSlider.setTextBoxStyle (Slider::TextBoxBelow, true, 40, 20);
     mSustainSlider.setColour (Slider::ColourIds::thumbColourId, Colours::red);
     mSustainSlider.setRange (0.0f, 1.0f, 0.01f);
+    mSustainSlider.addListener (this);
     addAndMakeVisible (mSustainSlider);

     mSustainLabel.setFont (10.0f);
@@ -59,6 +62,7 @@ HelloSamplerAudioProcessorEditor::HelloSamplerAudioProcessorEditor (HelloSampler
     mReleaseSlider.setTextBoxStyle (Slider::TextBoxBelow, true, 40, 20);
     mReleaseSlider.setColour (Slider::ColourIds::thumbColourId, Colours::red);
     mReleaseSlider.setRange (0.0f, 5.0f, 0.01f);
+    mReleaseSlider.addListener (this);
     addAndMakeVisible (mReleaseSlider);

     mReleaseLabel.setFont (10.0f);
@@ -164,3 +168,23 @@ void HelloSamplerAudioProcessorEditor::filesDropped (const StringArray& files, i

     repaint();
 }
+
+void HelloSamplerAudioProcessorEditor::sliderValueChanged (Slider* slider)
+{
+    if (slider == &mAttackSlider)
+    {
+        processor.attack = mAttackSlider.getValue();
+    }
+    else if (slider == &mDecaySlider)
+    {
+        processor.decay = mDecaySlider.getValue();
+    }
+    else if (slider == &mSustainSlider)
+    {
+        processor.sustain = mSustainSlider.getValue();
+    }
+    else if (slider == &mReleaseSlider)
+    {
+        processor.release = mReleaseSlider.getValue();
+    }
+}
diff –git a/Source/[PluginEditor](PluginEditor).h b/Source/[PluginEditor](PluginEditor).h index 98630cc..14872d2 100644
--- a/Source/PluginEditor.h
+++ b/Source/PluginEditor.h
@@ -17,7 +17,8 @@
 /**
 */
 class HelloSamplerAudioProcessorEditor  : public AudioProcessorEditor,
-                                          public FileDragAndDropTarget
+                                          public FileDragAndDropTarget,
+                                          public Slider::Listener
 {
 public:
     HelloSamplerAudioProcessorEditor (HelloSamplerAudioProcessor&);
@@ -29,6 +30,8 @@ public:

     bool isInterestedInFileDrag (const StringArray& files) override;
     void filesDropped (const StringArray& files, int x, int y) override;
+    
+    void sliderValueChanged (Slider* slider) override;

 private:
     TextButton mLoadButton { "Load" };
diff –git a/Source/[PluginProcessor](PluginProcessor).cpp b/Source/[PluginProcessor](PluginProcessor).cpp index bf97e42..8341563 100644
--- a/Source/PluginProcessor.cpp
+++ b/Source/PluginProcessor.cpp
@@ -140,6 +140,8 @@ void HelloSamplerAudioProcessor::processBlock (AudioBuffer<float>& buffer, MidiB
     ScopedNoDenormals noDenormals;
     auto totalNumInputChannels  = getTotalNumInputChannels();
     auto totalNumOutputChannels = getTotalNumOutputChannels();
+    
+    getADSRValue();

     for (auto i = totalNumInputChannels; i < totalNumOutputChannels; ++i)
         buffer.clear (i, 0, buffer.getNumSamples());
@@ -208,6 +210,11 @@ void HelloSamplerAudioProcessor::loadFile (const String& path)
     mSampler.addSound (new SamplerSound ("Sample", *mFormatReader, range, 60, 0.1, 0.1, 10.0));
 }

+void HelloSamplerAudioProcessor::getADSRValue()
+{
+    DBG ("Attack: " << attack << " Decay: " << decay << " Sustain: " << sustain << " Release: " << release);
+}
+
 //==============================================================================
 // This creates new instances of the plugin..
 AudioProcessor* JUCE_CALLTYPE createPluginFilter()
diff –git a/Source/[PluginProcessor](PluginProcessor).h b/Source/[PluginProcessor](PluginProcessor).h index c8ef3b8..fc2283b 100644
--- a/Source/PluginProcessor.h
+++ b/Source/PluginProcessor.h
@@ -60,6 +60,13 @@ public:

     int getNumSamplerSounds() { return mSampler.getNumSounds(); }
     AudioBuffer<float>& getWaveForm() { return mWaveForm; }
+    
+    void getADSRValue();
+    
+    float attack { 0.0 };
+    float decay { 0.0 };
+    float sustain { 0.0 };
+    float release { 0.0 };

 private:
     Synthesiser mSampler;

Diff 0: dacfb9c75d4288e4f199df9f33682945c6b59c12 to a5bcea55e10d3ca14893c60ffe1ef6b2633a6009

index 892971d..0f905df 100644 — a/Source/[PluginEditor](PluginEditor).cpp
+++ b/Source/PluginEditor.cpp
@@ -173,18 +173,20 @@ void HelloSamplerAudioProcessorEditor::sliderValueChanged (Slider* slider)
 {
     if (slider == &mAttackSlider)
     {
-        processor.attack = mAttackSlider.getValue();
+        processor.getADSRParams().attack = mAttackSlider.getValue();
     }
     else if (slider == &mDecaySlider)
     {
-        processor.decay = mDecaySlider.getValue();
+        processor.getADSRParams().decay = mDecaySlider.getValue();
     }
     else if (slider == &mSustainSlider)
     {
-        processor.sustain = mSustainSlider.getValue();
+        processor.getADSRParams().sustain = mSustainSlider.getValue();
     }
     else if (slider == &mReleaseSlider)
     {
-        processor.release = mReleaseSlider.getValue();
+        processor.getADSRParams().release = mReleaseSlider.getValue();
     }
+    
+    processor.updateADSR();
 }
diff –git a/Source/[PluginProcessor](PluginProcessor).cpp b/Source/[PluginProcessor](PluginProcessor).cpp index 8341563..a220897 100644
--- a/Source/PluginProcessor.cpp
+++ b/Source/PluginProcessor.cpp
@@ -103,6 +103,7 @@ void HelloSamplerAudioProcessor::changeProgramName (int index, const String& new
 void HelloSamplerAudioProcessor::prepareToPlay (double sampleRate, int samplesPerBlock)
 {
     mSampler.setCurrentPlaybackSampleRate (sampleRate);
+    updateADSR();
 }

 void HelloSamplerAudioProcessor::releaseResources()
@@ -140,8 +141,6 @@ void HelloSamplerAudioProcessor::processBlock (AudioBuffer<float>& buffer, MidiB
     ScopedNoDenormals noDenormals;
     auto totalNumInputChannels  = getTotalNumInputChannels();
     auto totalNumOutputChannels = getTotalNumOutputChannels();
-    
-    getADSRValue();

     for (auto i = totalNumInputChannels; i < totalNumOutputChannels; ++i)
         buffer.clear (i, 0, buffer.getNumSamples());
@@ -210,9 +209,15 @@ void HelloSamplerAudioProcessor::loadFile (const String& path)
     mSampler.addSound (new SamplerSound ("Sample", *mFormatReader, range, 60, 0.1, 0.1, 10.0));
 }

-void HelloSamplerAudioProcessor::getADSRValue()
+void HelloSamplerAudioProcessor::updateADSR()
 {
-    DBG ("Attack: " << attack << " Decay: " << decay << " Sustain: " << sustain << " Release: " << release);
+    for (int i = 0; i < mSampler.getNumSounds(); ++i)
+    {
+        if (auto sound = dynamic_cast<SamplerSound*>(mSampler.getSound(i).get()))
+        {
+            sound->setEnvelopeParameters (mADSRParams);
+        }
+    }
 }

 //==============================================================================
diff –git a/Source/[PluginProcessor](PluginProcessor).h b/Source/[PluginProcessor](PluginProcessor).h index fc2283b..dc92e83 100644
--- a/Source/PluginProcessor.h
+++ b/Source/PluginProcessor.h
@@ -61,18 +61,17 @@ public:
     int getNumSamplerSounds() { return mSampler.getNumSounds(); }
     AudioBuffer<float>& getWaveForm() { return mWaveForm; }

-    void getADSRValue();
+    void updateADSR();

-    float attack { 0.0 };
-    float decay { 0.0 };
-    float sustain { 0.0 };
-    float release { 0.0 };
+    ADSR::Parameters& getADSRParams() { return mADSRParams; }

 private:
     Synthesiser mSampler;
     const int mNumVoices { 3 };
     AudioBuffer<float> mWaveForm;

+    ADSR::Parameters mADSRParams;
+    
     AudioFormatManager mFormatManager;
     AudioFormatReader* mFormatReader { nullptr };

Diff 0: a5bcea55e10d3ca14893c60ffe1ef6b2633a6009 to 4f1cc61b0c309abd6336c9599faca10ca020d024

index 0f905df..039a547 100644 — a/Source/[PluginEditor](PluginEditor).cpp
+++ b/Source/PluginEditor.cpp
@@ -22,8 +22,7 @@ HelloSamplerAudioProcessorEditor::HelloSamplerAudioProcessorEditor (HelloSampler
     mAttackSlider.setSliderStyle (Slider::SliderStyle::RotaryVerticalDrag);
     mAttackSlider.setTextBoxStyle (Slider::TextBoxBelow, true, 40, 20);
     mAttackSlider.setColour (Slider::ColourIds::thumbColourId, Colours::red);
-    mAttackSlider.setRange (0.0f, 5.0f, 0.01f);
-    mAttackSlider.addListener (this);
+    //mAttackSlider.setRange (0.0f, 5.0f, 0.01f);
     addAndMakeVisible (mAttackSlider);

     mAttackLabel.setFont (10.0f);
@@ -31,12 +30,13 @@ HelloSamplerAudioProcessorEditor::HelloSamplerAudioProcessorEditor (HelloSampler
     mAttackLabel.setJustificationType (Justification::centredTop);
     mAttackLabel.attachToComponent (&mAttackSlider, false);

+    mAttackAttachment = std::make_unique<AudioProcessorValueTreeState::SliderAttachment>(processor.getValueTree(), "ATTACK", mAttackSlider);
+    
     //Decay Slider
     mDecaySlider.setSliderStyle (Slider::SliderStyle::RotaryVerticalDrag);
     mDecaySlider.setTextBoxStyle (Slider::TextBoxBelow, true, 40, 20);
     mDecaySlider.setColour (Slider::ColourIds::thumbColourId, Colours::red);
-    mDecaySlider.setRange (0.0f, 5.0f, 0.01f);
-    mDecaySlider.addListener (this);
+    //mDecaySlider.setRange (0.0f, 5.0f, 0.01f);
     addAndMakeVisible (mDecaySlider);

     mDecayLabel.setFont (10.0f);
@@ -44,12 +44,13 @@ HelloSamplerAudioProcessorEditor::HelloSamplerAudioProcessorEditor (HelloSampler
     mDecayLabel.setJustificationType (Justification::centredTop);
     mDecayLabel.attachToComponent (&mDecaySlider, false);

+    mDecayAttachment = std::make_unique<AudioProcessorValueTreeState::SliderAttachment>(processor.getValueTree(), "DECAY", mDecaySlider);
+    
     //Sustain Slider
     mSustainSlider.setSliderStyle (Slider::SliderStyle::RotaryVerticalDrag);
     mSustainSlider.setTextBoxStyle (Slider::TextBoxBelow, true, 40, 20);
     mSustainSlider.setColour (Slider::ColourIds::thumbColourId, Colours::red);
-    mSustainSlider.setRange (0.0f, 1.0f, 0.01f);
-    mSustainSlider.addListener (this);
+    //mSustainSlider.setRange (0.0f, 1.0f, 0.01f);
     addAndMakeVisible (mSustainSlider);

     mSustainLabel.setFont (10.0f);
@@ -57,12 +58,13 @@ HelloSamplerAudioProcessorEditor::HelloSamplerAudioProcessorEditor (HelloSampler
     mSustainLabel.setJustificationType (Justification::centredTop);
     mSustainLabel.attachToComponent (&mSustainSlider, false);

+    mSustainAttachment = std::make_unique<AudioProcessorValueTreeState::SliderAttachment>(processor.getValueTree(), "SUSTAIN", mSustainSlider);
+    
     //Release Slider
     mReleaseSlider.setSliderStyle (Slider::SliderStyle::RotaryVerticalDrag);
     mReleaseSlider.setTextBoxStyle (Slider::TextBoxBelow, true, 40, 20);
     mReleaseSlider.setColour (Slider::ColourIds::thumbColourId, Colours::red);
-    mReleaseSlider.setRange (0.0f, 5.0f, 0.01f);
-    mReleaseSlider.addListener (this);
+    //mReleaseSlider.setRange (0.0f, 5.0f, 0.01f);
     addAndMakeVisible (mReleaseSlider);

     mReleaseLabel.setFont (10.0f);
@@ -70,6 +72,8 @@ HelloSamplerAudioProcessorEditor::HelloSamplerAudioProcessorEditor (HelloSampler
     mReleaseLabel.setJustificationType (Justification::centredTop);
     mReleaseLabel.attachToComponent (&mReleaseSlider, false);

+    mReleaseAttachment = std::make_unique<AudioProcessorValueTreeState::SliderAttachment>(processor.getValueTree(), "RELEASE", mReleaseSlider);
+    
     setSize (600, 200);
 }

@@ -169,24 +173,3 @@ void HelloSamplerAudioProcessorEditor::filesDropped (const StringArray& files, i
     repaint();
 }

-void HelloSamplerAudioProcessorEditor::sliderValueChanged (Slider* slider)
-{
-    if (slider == &mAttackSlider)
-    {
-        processor.getADSRParams().attack = mAttackSlider.getValue();
-    }
-    else if (slider == &mDecaySlider)
-    {
-        processor.getADSRParams().decay = mDecaySlider.getValue();
-    }
-    else if (slider == &mSustainSlider)
-    {
-        processor.getADSRParams().sustain = mSustainSlider.getValue();
-    }
-    else if (slider == &mReleaseSlider)
-    {
-        processor.getADSRParams().release = mReleaseSlider.getValue();
-    }
-    
-    processor.updateADSR();
-}
diff –git a/Source/[PluginEditor](PluginEditor).h b/Source/[PluginEditor](PluginEditor).h index 14872d2..e4ae2b6 100644
--- a/Source/PluginEditor.h
+++ b/Source/PluginEditor.h
@@ -17,8 +17,7 @@
 /**
 */
 class HelloSamplerAudioProcessorEditor  : public AudioProcessorEditor,
-                                          public FileDragAndDropTarget,
-                                          public Slider::Listener
+                                          public FileDragAndDropTarget
 {
 public:
     HelloSamplerAudioProcessorEditor (HelloSamplerAudioProcessor&);
@@ -30,8 +29,6 @@ public:

     bool isInterestedInFileDrag (const StringArray& files) override;
     void filesDropped (const StringArray& files, int x, int y) override;
-    
-    void sliderValueChanged (Slider* slider) override;

 private:
     TextButton mLoadButton { "Load" };
@@ -41,6 +38,11 @@ private:
     Slider mAttackSlider, mDecaySlider, mSustainSlider, mReleaseSlider;
     Label mAttackLabel, mDecayLabel, mSustainLabel, mReleaseLabel;

+    std::unique_ptr<AudioProcessorValueTreeState::SliderAttachment> mAttackAttachment;
+    std::unique_ptr<AudioProcessorValueTreeState::SliderAttachment> mDecayAttachment;
+    std::unique_ptr<AudioProcessorValueTreeState::SliderAttachment> mSustainAttachment;
+    std::unique_ptr<AudioProcessorValueTreeState::SliderAttachment> mReleaseAttachment;
+    
     HelloSamplerAudioProcessor& processor;

     JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (HelloSamplerAudioProcessorEditor)
diff –git a/Source/[PluginProcessor](PluginProcessor).cpp b/Source/[PluginProcessor](PluginProcessor).cpp index a220897..482282c 100644
--- a/Source/PluginProcessor.cpp
+++ b/Source/PluginProcessor.cpp
@@ -21,10 +21,11 @@ HelloSamplerAudioProcessor::HelloSamplerAudioProcessor()
                       #endif
                        .withOutput ("Output", AudioChannelSet::stereo(), true)
                      #endif
-                       )
+                       ), mAPVTS (*this, nullptr, "Parameters", createParameters())
 #endif
 {
     mFormatManager.registerBasicFormats();
+    mAPVTS.state.addListener (this);

     for (int i = 0; i < mNumVoices; i++)
     {
@@ -34,6 +35,7 @@ HelloSamplerAudioProcessor::HelloSamplerAudioProcessor()

 HelloSamplerAudioProcessor::~HelloSamplerAudioProcessor()
 {
+    mAPVTS.state.removeListener (this);
     mFormatReader = nullptr;
 }

@@ -144,6 +146,11 @@ void HelloSamplerAudioProcessor::processBlock (AudioBuffer<float>& buffer, MidiB

     for (auto i = totalNumInputChannels; i < totalNumOutputChannels; ++i)
         buffer.clear (i, 0, buffer.getNumSamples());
+    
+    if (mShouldUpdate)
+    {
+        updateADSR();
+    }

     mSampler.renderNextBlock (buffer, midiMessages, 0, buffer.getNumSamples());
 }
@@ -207,10 +214,19 @@ void HelloSamplerAudioProcessor::loadFile (const String& path)
     range.setRange (0, 128, true);

     mSampler.addSound (new SamplerSound ("Sample", *mFormatReader, range, 60, 0.1, 0.1, 10.0));
+    
+    updateADSR();
 }

 void HelloSamplerAudioProcessor::updateADSR()
 {
+    mShouldUpdate = false;
+    
+    mADSRParams.attack = mAPVTS.getRawParameterValue ("ATTACK")->load();
+    mADSRParams.decay = mAPVTS.getRawParameterValue ("DECAY")->load();
+    mADSRParams.sustain = mAPVTS.getRawParameterValue ("SUSTAIN")->load();
+    mADSRParams.release = mAPVTS.getRawParameterValue ("RELEASE")->load();
+    
     for (int i = 0; i < mSampler.getNumSounds(); ++i)
     {
         if (auto sound = dynamic_cast<SamplerSound*>(mSampler.getSound(i).get()))
@@ -220,6 +236,23 @@ void HelloSamplerAudioProcessor::updateADSR()
     }
 }

+AudioProcessorValueTreeState::ParameterLayout HelloSamplerAudioProcessor::createParameters()
+{
+    std::vector<std::unique_ptr<RangedAudioParameter>> params;
+    
+    params.push_back (std::make_unique<AudioParameterFloat>("ATTACK", "Attack", 0.0f, 5.0f, 0.0f));
+    params.push_back (std::make_unique<AudioParameterFloat>("DECAY", "Decay", 0.0f, 5.0f, 2.0f));
+    params.push_back (std::make_unique<AudioParameterFloat>("SUSTAIN", "Sustain", 0.0f, 1.0f, 1.0f));
+    params.push_back (std::make_unique<AudioParameterFloat>("RELEASE", "Release", 0.0f, 5.0f, 0.0f));
+    
+    return { params.begin(), params.end() };
+}
+
+void HelloSamplerAudioProcessor::valueTreePropertyChanged (ValueTree &treeWhosePropertyHasChanged, const Identifier &property)
+{
+    mShouldUpdate = true;
+}
+
 //==============================================================================
 // This creates new instances of the plugin..
 AudioProcessor* JUCE_CALLTYPE createPluginFilter()
diff –git a/Source/[PluginProcessor](PluginProcessor).h b/Source/[PluginProcessor](PluginProcessor).h index dc92e83..a89449d 100644
--- a/Source/PluginProcessor.h
+++ b/Source/PluginProcessor.h
@@ -15,7 +15,8 @@
 //==============================================================================
 /**
 */
-class HelloSamplerAudioProcessor  : public AudioProcessor
+class HelloSamplerAudioProcessor  : public AudioProcessor,
+                                    public ValueTree::Listener
 {
 public:
     //==============================================================================
@@ -62,8 +63,9 @@ public:
     AudioBuffer<float>& getWaveForm() { return mWaveForm; }

     void updateADSR();
-    
     ADSR::Parameters& getADSRParams() { return mADSRParams; }
+    
+    AudioProcessorValueTreeState& getValueTree() { return mAPVTS; }

 private:
     Synthesiser mSampler;
@@ -75,6 +77,12 @@ private:
     AudioFormatManager mFormatManager;
     AudioFormatReader* mFormatReader { nullptr };

+    AudioProcessorValueTreeState mAPVTS;
+    AudioProcessorValueTreeState::ParameterLayout createParameters();
+    void valueTreePropertyChanged (ValueTree &treeWhosePropertyHasChanged, const Identifier &property) override;
+    
+    std::atomic<bool> mShouldUpdate { false };
+    
     //==============================================================================
     JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (HelloSamplerAudioProcessor)
 };

Diff 0: 4f1cc61b0c309abd6336c9599faca10ca020d024 to c5b87db793ed6e6a46eeb17bf4044b6871d924ee

index 6a7eb89..3f5085d 100644 — a/Source/[ADSRComponent](ADSRComponent).cpp
+++ b/Source/ADSRComponent.cpp
@@ -2,7 +2,7 @@
   ==============================================================================

     ADSRComponent.cpp
-    Created: 14 Mar 2020 2:52:49pm
+    Created: 4 Apr 2020 7:35:53pm
     Author:  Joshua Hodge

   ==============================================================================
@@ -14,35 +14,61 @@
 //==============================================================================
 ADSRComponent::ADSRComponent (HelloSamplerAudioProcessor& p) : processor (p)
 {
-    mAttackSlider.setRange (0.1f, 2.0f, 0.01f);
-    mAttackSlider.setValue (0.1f);
+    //Attack Slider
     mAttackSlider.setSliderStyle (Slider::SliderStyle::RotaryVerticalDrag);
-    mAttackSlider.setTextBoxStyle (Slider::TextBoxBelow, true, 35, 20);
+    mAttackSlider.setTextBoxStyle (Slider::TextBoxBelow, true, 40, 20);
+    mAttackSlider.setColour (Slider::ColourIds::thumbColourId, Colours::red);
+    //mAttackSlider.setRange (0.0f, 5.0f, 0.01f);
     addAndMakeVisible (mAttackSlider);
-    mAttackSlider.addListener (this);

-    mDecaySlider.setRange (0.1f, 1.0f, 0.01f);
-    mDecaySlider.setValue (0.1f);
+    mAttackLabel.setFont (10.0f);
+    mAttackLabel.setText ("Attack", NotificationType::dontSendNotification);
+    mAttackLabel.setJustificationType (Justification::centredTop);
+    mAttackLabel.attachToComponent (&mAttackSlider, false);
+    
+    mAttackAttachment = std::make_unique<AudioProcessorValueTreeState::SliderAttachment>(processor.getValueTree(), "ATTACK", mAttackSlider);
+    
+    //Decay Slider
     mDecaySlider.setSliderStyle (Slider::SliderStyle::RotaryVerticalDrag);
-    mDecaySlider.setTextBoxStyle (Slider::TextBoxBelow, true, 35, 20);
+    mDecaySlider.setTextBoxStyle (Slider::TextBoxBelow, true, 40, 20);
+    mDecaySlider.setColour (Slider::ColourIds::thumbColourId, Colours::red);
+    //mDecaySlider.setRange (0.0f, 5.0f, 0.01f);
     addAndMakeVisible (mDecaySlider);
-    mDecaySlider.addListener (this);

-    mSustainSlider.setRange (0.1f, 1.0f, 0.01f);
-    mSustainSlider.setValue (1.0f);
+    mDecayLabel.setFont (10.0f);
+    mDecayLabel.setText ("Decay", NotificationType::dontSendNotification);
+    mDecayLabel.setJustificationType (Justification::centredTop);
+    mDecayLabel.attachToComponent (&mDecaySlider, false);
+    
+    mDecayAttachment = std::make_unique<AudioProcessorValueTreeState::SliderAttachment>(processor.getValueTree(), "DECAY", mDecaySlider);
+    
+    //Sustain Slider
     mSustainSlider.setSliderStyle (Slider::SliderStyle::RotaryVerticalDrag);
-    mSustainSlider.setTextBoxStyle (Slider::TextBoxBelow, true, 35, 20);
+    mSustainSlider.setTextBoxStyle (Slider::TextBoxBelow, true, 40, 20);
+    mSustainSlider.setColour (Slider::ColourIds::thumbColourId, Colours::red);
+    //mSustainSlider.setRange (0.0f, 1.0f, 0.01f);
     addAndMakeVisible (mSustainSlider);
-    mSustainSlider.addListener (this);

-    mReleaseSlider.setRange (0.1f, 5.0f, 0.01f);
-    mReleaseSlider.setValue (0.4f);
+    mSustainLabel.setFont (10.0f);
+    mSustainLabel.setText ("Sustain", NotificationType::dontSendNotification);
+    mSustainLabel.setJustificationType (Justification::centredTop);
+    mSustainLabel.attachToComponent (&mSustainSlider, false);
+    
+    mSustainAttachment = std::make_unique<AudioProcessorValueTreeState::SliderAttachment>(processor.getValueTree(), "SUSTAIN", mSustainSlider);
+    
+    //Release Slider
     mReleaseSlider.setSliderStyle (Slider::SliderStyle::RotaryVerticalDrag);
-    mReleaseSlider.setTextBoxStyle (Slider::TextBoxBelow, true, 35, 20);
+    mReleaseSlider.setTextBoxStyle (Slider::TextBoxBelow, true, 40, 20);
+    mReleaseSlider.setColour (Slider::ColourIds::thumbColourId, Colours::red);
+    //mReleaseSlider.setRange (0.0f, 5.0f, 0.01f);
     addAndMakeVisible (mReleaseSlider);
-    mReleaseSlider.addListener (this);

-    setSize (400, 200);
+    mReleaseLabel.setFont (10.0f);
+    mReleaseLabel.setText ("Release", NotificationType::dontSendNotification);
+    mReleaseLabel.setJustificationType (Justification::centredTop);
+    mReleaseLabel.attachToComponent (&mReleaseSlider, false);
+    
+    mReleaseAttachment = std::make_unique<AudioProcessorValueTreeState::SliderAttachment>(processor.getValueTree(), "RELEASE", mReleaseSlider);
 }

 ADSRComponent::~ADSRComponent()
@@ -51,40 +77,18 @@ ADSRComponent::~ADSRComponent()

 void ADSRComponent::paint (Graphics& g)
 {
-    g.fillAll (Colours::orangered);
+    g.fillAll (Colours::black);
 }

 void ADSRComponent::resized()
 {
-    const auto dialSizeX = 0.25f;
-    const auto dialSizeY = 0.6f;
-    const auto yPosition = 0.2f;
-    
-    mAttackSlider.setBoundsRelative (0.0f, yPosition, dialSizeX, dialSizeY);
-    mDecaySlider.setBoundsRelative (0.25f, yPosition, dialSizeX, dialSizeY);
-    mSustainSlider.setBoundsRelative (0.5f, yPosition, dialSizeX, dialSizeY);
-    mReleaseSlider.setBoundsRelative (0.75f, yPosition, dialSizeX, dialSizeY);
-}
-
-void ADSRComponent::sliderValueChanged (Slider *slider)
-{
-    if (slider == &mAttackSlider)
-    {
-        processor.setADSRAttack (mAttackSlider.getValue());
-    }
-    
-    if (slider == &mDecaySlider)
-    {
-        processor.setADSRDecay (mDecaySlider.getValue());
-    }
-    
-    if (slider == &mSustainSlider)
-    {
-        processor.setADSRSustain (mSustainSlider.getValue());
-    }
+    const auto startX = 0.6f;
+    const auto startY = 0.2f;
+    const auto dialWidth = 0.1f;
+    const auto dialHeight = 0.75f;

-    if (slider == &mReleaseSlider)
-    {
-        processor.setADSRRelease (mReleaseSlider.getValue());
-    }
+    mAttackSlider.setBoundsRelative (startX, startY, dialWidth, dialHeight);
+    mDecaySlider.setBoundsRelative (startX + dialWidth, startY, dialWidth, dialHeight);
+    mSustainSlider.setBoundsRelative (startX + (dialWidth * 2), startY, dialWidth, dialHeight);
+    mReleaseSlider.setBoundsRelative (startX + (dialWidth * 3), startY, dialWidth, dialHeight);
 }
diff –git a/Source/[ADSRComponent](ADSRComponent).h b/Source/[ADSRComponent](ADSRComponent).h index 66ea725..daf48ba 100644
--- a/Source/ADSRComponent.h
+++ b/Source/ADSRComponent.h
@@ -2,7 +2,7 @@
   ==============================================================================

     ADSRComponent.h
-    Created: 14 Mar 2020 2:52:49pm
+    Created: 4 Apr 2020 7:35:53pm
     Author:  Joshua Hodge

   ==============================================================================
@@ -13,11 +13,11 @@
 #include <JuceHeader.h>
 #include "PluginProcessor.h"

+
 //==============================================================================
 /*
 */
-class ADSRComponent : public Component,
-                      public Slider::Listener
+class ADSRComponent    : public Component
 {
 public:
     ADSRComponent (HelloSamplerAudioProcessor& p);
@@ -25,21 +25,17 @@ public:

     void paint (Graphics&) override;
     void resized() override;
-    
-    void sliderValueChanged (Slider *slider) override;
-    
-    Slider& getAttackSlider() { return mAttackSlider; }
-    Slider& getDecaySlider() { return mDecaySlider; }
-    Slider& getSustainSlider() { return mSustainSlider; }
-    Slider& getReleaseSlider() { return mReleaseSlider; }

 private:
-    Slider mAttackSlider;
-    Slider mDecaySlider;
-    Slider mSustainSlider;
-    Slider mReleaseSlider;
+    Slider mAttackSlider, mDecaySlider, mSustainSlider, mReleaseSlider;
+    Label mAttackLabel, mDecayLabel, mSustainLabel, mReleaseLabel;
+    
+    std::unique_ptr<AudioProcessorValueTreeState::SliderAttachment> mAttackAttachment;
+    std::unique_ptr<AudioProcessorValueTreeState::SliderAttachment> mDecayAttachment;
+    std::unique_ptr<AudioProcessorValueTreeState::SliderAttachment> mSustainAttachment;
+    std::unique_ptr<AudioProcessorValueTreeState::SliderAttachment> mReleaseAttachment;

     HelloSamplerAudioProcessor& processor;
-        
+    
     JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ADSRComponent)
 };
diff –git a/Source/[MySampler](MySampler).cpp b/Source/[MySampler](MySampler).cpp deleted file mode 100644
index edc6018..0000000
--- a/Source/MySampler.cpp
+++ /dev/null
@@ -1,11 +0,0 @@
-/*
-  ==============================================================================
-
-    MySampler.cpp
-    Created: 14 Mar 2020 1:41:28pm
-    Author:  Joshua Hodge
-
-  ==============================================================================
-*/
-
-#include "MySampler.h"
diff –git a/Source/[MySampler](MySampler).h b/Source/[MySampler](MySampler).h deleted file mode 100644
index adb1b93..0000000
--- a/Source/MySampler.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
-  ==============================================================================
-
-    MySampler.h
-    Created: 14 Mar 2020 1:41:28pm
-    Author:  Joshua Hodge
-
-  ==============================================================================
-*/
-
-#pragma once
-#include <JuceHeader.h>
-
-class MySampler : public Synthesiser
-{
-public:
-    void handleMidiEvent (const MidiMessage &m) override
-    {
-        const int channel = m.getChannel();
-        
-        if (m.isNoteOn())
-        {
-            noteOn (channel, m.getNoteNumber(), m.getFloatVelocity());
-            mADSR.noteOn();
-        }
-        else if (m.isNoteOff())
-        {
-            noteOff (channel, m.getNoteNumber(), m.getFloatVelocity(), true);
-            mADSR.noteOff();
-        }
-    }
-
-    //public methods
-    
-    void prepareToPlay (int sampleRate)
-    {
-        setCurrentPlaybackSampleRate (sampleRate);
-        mADSR.setSampleRate (sampleRate);
-        mADSR.setParameters (mADSRParams);
-    }
-    
-    void getNextAudioBlock (AudioBuffer<float>& buffer, const MidiBuffer& midiMessages, int startSample, int numSamples)
-    {
-        renderNextBlock (buffer, midiMessages, startSample, numSamples);
-        mADSR.applyEnvelopeToBuffer (buffer, startSample, numSamples);
-    }
-    
-    //Access methods
-    ADSR& getADSR() { return mADSR; }
-    ADSR::Parameters& getADSRParams() { return mADSRParams; }
-    
-private:
-    ADSR mADSR;
-    ADSR::Parameters mADSRParams;
-};
diff –git a/Source/[PluginEditor](PluginEditor).cpp b/Source/[PluginEditor](PluginEditor).cpp index 039a547..f5f54d5 100644
--- a/Source/PluginEditor.cpp
+++ b/Source/PluginEditor.cpp
@@ -13,68 +13,11 @@

 //==============================================================================
 HelloSamplerAudioProcessorEditor::HelloSamplerAudioProcessorEditor (HelloSamplerAudioProcessor& p)
-    : AudioProcessorEditor (&p), processor (p)
+    : AudioProcessorEditor (&p), mWaveThumbnail (p), mADSR (p), processor (p)
 {
-    mLoadButton.onClick = [&]() { processor.loadFile(); };
-    addAndMakeVisible (mLoadButton);
-    
-    //Attack Slider
-    mAttackSlider.setSliderStyle (Slider::SliderStyle::RotaryVerticalDrag);
-    mAttackSlider.setTextBoxStyle (Slider::TextBoxBelow, true, 40, 20);
-    mAttackSlider.setColour (Slider::ColourIds::thumbColourId, Colours::red);
-    //mAttackSlider.setRange (0.0f, 5.0f, 0.01f);
-    addAndMakeVisible (mAttackSlider);
-    
-    mAttackLabel.setFont (10.0f);
-    mAttackLabel.setText ("Attack", NotificationType::dontSendNotification);
-    mAttackLabel.setJustificationType (Justification::centredTop);
-    mAttackLabel.attachToComponent (&mAttackSlider, false);
-    
-    mAttackAttachment = std::make_unique<AudioProcessorValueTreeState::SliderAttachment>(processor.getValueTree(), "ATTACK", mAttackSlider);
-    
-    //Decay Slider
-    mDecaySlider.setSliderStyle (Slider::SliderStyle::RotaryVerticalDrag);
-    mDecaySlider.setTextBoxStyle (Slider::TextBoxBelow, true, 40, 20);
-    mDecaySlider.setColour (Slider::ColourIds::thumbColourId, Colours::red);
-    //mDecaySlider.setRange (0.0f, 5.0f, 0.01f);
-    addAndMakeVisible (mDecaySlider);
-    
-    mDecayLabel.setFont (10.0f);
-    mDecayLabel.setText ("Decay", NotificationType::dontSendNotification);
-    mDecayLabel.setJustificationType (Justification::centredTop);
-    mDecayLabel.attachToComponent (&mDecaySlider, false);
-    
-    mDecayAttachment = std::make_unique<AudioProcessorValueTreeState::SliderAttachment>(processor.getValueTree(), "DECAY", mDecaySlider);
-    
-    //Sustain Slider
-    mSustainSlider.setSliderStyle (Slider::SliderStyle::RotaryVerticalDrag);
-    mSustainSlider.setTextBoxStyle (Slider::TextBoxBelow, true, 40, 20);
-    mSustainSlider.setColour (Slider::ColourIds::thumbColourId, Colours::red);
-    //mSustainSlider.setRange (0.0f, 1.0f, 0.01f);
-    addAndMakeVisible (mSustainSlider);
-    
-    mSustainLabel.setFont (10.0f);
-    mSustainLabel.setText ("Sustain", NotificationType::dontSendNotification);
-    mSustainLabel.setJustificationType (Justification::centredTop);
-    mSustainLabel.attachToComponent (&mSustainSlider, false);
-    
-    mSustainAttachment = std::make_unique<AudioProcessorValueTreeState::SliderAttachment>(processor.getValueTree(), "SUSTAIN", mSustainSlider);
-    
-    //Release Slider
-    mReleaseSlider.setSliderStyle (Slider::SliderStyle::RotaryVerticalDrag);
-    mReleaseSlider.setTextBoxStyle (Slider::TextBoxBelow, true, 40, 20);
-    mReleaseSlider.setColour (Slider::ColourIds::thumbColourId, Colours::red);
-    //mReleaseSlider.setRange (0.0f, 5.0f, 0.01f);
-    addAndMakeVisible (mReleaseSlider);
-    
-    mReleaseLabel.setFont (10.0f);
-    mReleaseLabel.setText ("Release", NotificationType::dontSendNotification);
-    mReleaseLabel.setJustificationType (Justification::centredTop);
-    mReleaseLabel.attachToComponent (&mReleaseSlider, false);
-    
-    mReleaseAttachment = std::make_unique<AudioProcessorValueTreeState::SliderAttachment>(processor.getValueTree(), "RELEASE", mReleaseSlider);
-    
-    setSize (600, 200);
+    addAndMakeVisible (mWaveThumbnail);
+    addAndMakeVisible (mADSR);
+    setSize (600, 400);
 }

 HelloSamplerAudioProcessorEditor::~HelloSamplerAudioProcessorEditor()
@@ -85,91 +28,13 @@ HelloSamplerAudioProcessorEditor::~HelloSamplerAudioProcessorEditor()
 void HelloSamplerAudioProcessorEditor::paint (Graphics& g)
 {
     g.fillAll (Colours::black);
-    g.setColour (Colours::white);
-    
-    if (mShouldBePainting)
-    {
-        Path p;
-        mAudioPoints.clear();
-        
-        auto waveform = processor.getWaveForm();
-        auto ratio = waveform.getNumSamples() / getWidth();
-        auto buffer = waveform.getReadPointer (0);
-    
-        //scale audio file to window on x axis
-        for (int sample = 0; sample < waveform.getNumSamples(); sample+=ratio)
-        {
-            mAudioPoints.push_back (buffer[sample]);
-        }
-    
-        p.startNewSubPath (0, getHeight() / 2);
-    
-        //scale on y axis
-        for (int sample = 0; sample < mAudioPoints.size(); ++sample)
-        {
-            auto point = jmap<float> (mAudioPoints[sample], -1.0f, 1.0f, 200, 0);
-            p.lineTo (sample, point);
-        }
-    
-        g.strokePath(p, PathStrokeType (2));
-    
-        mShouldBePainting = false;
-    }
-    
-    
-//    g.setColour (Colours::white);
-//    g.setFont (15.0f);
-//
-//    if (processor.getNumSamplerSounds() > 0)
-//    {
-//        g.fillAll (Colours::red);
-//        g.drawText ("Sound Loaded", getWidth() / 2 - 50, getHeight() / 2 - 10, 100, 20, Justification::centred);
-//    }
-//    else
-//    {
-//        g.drawText ("Load a Sound", getWidth() / 2 - 50, getHeight() / 2 - 10, 100, 20, Justification::centred);
-//    }
 }

 void HelloSamplerAudioProcessorEditor::resized()
 {
-    //mLoadButton.setBounds (getWidth() / 2 - 50, getHeight() / 2 - 50, 100, 100);
-    
-    const auto startX = 0.6f;
-    const auto startY = 0.6f;
-    const auto dialWidth = 0.1f;
-    const auto dialHeight = 0.4f;
-    
-    mAttackSlider.setBoundsRelative (startX, startY, dialWidth, dialHeight);
-    mDecaySlider.setBoundsRelative (startX + dialWidth, startY, dialWidth, dialHeight);
-    mSustainSlider.setBoundsRelative (startX + (dialWidth * 2), startY, dialWidth, dialHeight);
-    mReleaseSlider.setBoundsRelative (startX + (dialWidth * 3), startY, dialWidth, dialHeight);
+    mWaveThumbnail.setBoundsRelative (0.0f, 0.25f, 1.0f, 0.5);
+    mADSR.setBoundsRelative (0.0f, 0.75f, 1.0f, 0.25f);
 }

-bool HelloSamplerAudioProcessorEditor::isInterestedInFileDrag (const StringArray& files)
-{
-    for (auto file : files)
-    {
-        if (file.contains (".wav") || file.contains (".mp3") || file.contains (".aif"))
-        {
-            return true;
-        }
-    }
-    
-    return false;
-}

-void HelloSamplerAudioProcessorEditor::filesDropped (const StringArray& files, int x, int y)
-{
-    for (auto file : files)
-    {
-        if (isInterestedInFileDrag (file))
-        {
-            mShouldBePainting = true;
-            processor.loadFile (file);
-        }
-    }
-    
-    repaint();
-}
diff –git a/Source/[PluginEditor](PluginEditor).h b/Source/[PluginEditor](PluginEditor).h index e4ae2b6..cfbbb5a 100644
--- a/Source/PluginEditor.h
+++ b/Source/PluginEditor.h
@@ -12,12 +12,13 @@

 #include <JuceHeader.h>
 #include "PluginProcessor.h"
+#include "WaveThumbnail.h"
+#include "ADSRComponent.h"

 //==============================================================================
 /**
 */
-class HelloSamplerAudioProcessorEditor  : public AudioProcessorEditor,
-                                          public FileDragAndDropTarget
+class HelloSamplerAudioProcessorEditor  : public AudioProcessorEditor
 {
 public:
     HelloSamplerAudioProcessorEditor (HelloSamplerAudioProcessor&);
@@ -26,22 +27,10 @@ public:
     //==============================================================================
     void paint (Graphics&) override;
     void resized() override;
-    
-    bool isInterestedInFileDrag (const StringArray& files) override;
-    void filesDropped (const StringArray& files, int x, int y) override;

-private:
-    TextButton mLoadButton { "Load" };
-    std::vector<float> mAudioPoints;
-    bool mShouldBePainting { false };
-    
-    Slider mAttackSlider, mDecaySlider, mSustainSlider, mReleaseSlider;
-    Label mAttackLabel, mDecayLabel, mSustainLabel, mReleaseLabel;
-    
-    std::unique_ptr<AudioProcessorValueTreeState::SliderAttachment> mAttackAttachment;
-    std::unique_ptr<AudioProcessorValueTreeState::SliderAttachment> mDecayAttachment;
-    std::unique_ptr<AudioProcessorValueTreeState::SliderAttachment> mSustainAttachment;
-    std::unique_ptr<AudioProcessorValueTreeState::SliderAttachment> mReleaseAttachment;
+private:    
+    WaveThumbnail mWaveThumbnail;
+    ADSRComponent mADSR;

     HelloSamplerAudioProcessor& processor;
diff –git a/Source/[WaveThumbnail](WaveThumbnail).cpp b/Source/[WaveThumbnail](WaveThumbnail).cpp new file mode 100644
index 0000000..14bb904
--- /dev/null
+++ b/Source/WaveThumbnail.cpp
@@ -0,0 +1,106 @@
+/*
+  ==============================================================================
+
+    WaveThumbnail.cpp
+    Created: 4 Apr 2020 5:47:38pm
+    Author:  Joshua Hodge
+
+  ==============================================================================
+*/
+
+#include <JuceHeader.h>
+#include "WaveThumbnail.h"
+
+//==============================================================================
+WaveThumbnail::WaveThumbnail (HelloSamplerAudioProcessor& p) : processor (p)
+{
+    // In your constructor, you should add any child components, and
+    // initialise any special settings that your component needs.
+
+}
+
+WaveThumbnail::~WaveThumbnail()
+{
+}
+
+void WaveThumbnail::paint (Graphics& g)
+{
+    g.fillAll (Colours::cadetblue.darker());
+    
+    auto waveform = processor.getWaveForm();
+    
+    if (waveform.getNumSamples() > 0)
+    {
+        Path p;
+        mAudioPoints.clear();
+        
+        
+        auto ratio = waveform.getNumSamples() / getWidth();
+        auto buffer = waveform.getReadPointer (0);
+        
+        //scale audio file to window on x axis
+        for (int sample = 0; sample < waveform.getNumSamples(); sample+=ratio)
+        {
+            mAudioPoints.push_back (buffer[sample]);
+        }
+        
+        g.setColour (Colours::yellow);
+        p.startNewSubPath (0, getHeight() / 2);
+        
+        //scale on y axis
+        for (int sample = 0; sample < mAudioPoints.size(); ++sample)
+        {
+            auto point = jmap<float> (mAudioPoints[sample], -1.0f, 1.0f, getHeight(), 0);
+            p.lineTo (sample, point);
+        }
+        
+        g.strokePath(p, PathStrokeType (2));
+        
+        g.setColour (Colours::white);
+        g.setFont (15.0f);
+        auto textBounds = getLocalBounds().reduced (10, 10);
+        g.drawFittedText (mFileName, textBounds, Justification::topRight, 1);
+    }
+    else
+    {
+        g.setColour (Colours::white);
+        g.setFont (40.0f);
+        g.drawFittedText ("Drop an Audio File to Load", getLocalBounds(), Justification::centred, 1);
+    }
+}
+
+void WaveThumbnail::resized()
+{
+    // This method is where you should set the bounds of any child
+    // components that your component contains..
+
+}
+
+bool WaveThumbnail::isInterestedInFileDrag (const StringArray& files)
+{
+    for (auto file : files)
+    {
+        if (file.contains (".wav") || file.contains (".mp3") || file.contains (".aif"))
+        {
+            return true;
+        }
+    }
+    
+    return false;
+}
+
+void WaveThumbnail::filesDropped (const StringArray& files, int x, int y)
+{
+    for (auto file : files)
+    {
+        if (isInterestedInFileDrag (file))
+        {
+            auto myFile = std::make_unique<File>(file);
+            mFileName = myFile->getFileNameWithoutExtension();
+            
+            processor.loadFile (file);
+        }
+    }
+    
+    repaint();
+}
diff –git a/Source/[WaveThumbnail](WaveThumbnail).h b/Source/[WaveThumbnail](WaveThumbnail).h new file mode 100644
index 0000000..2a4b909
--- /dev/null
+++ b/Source/WaveThumbnail.h
@@ -0,0 +1,41 @@
+/*
+  ==============================================================================
+
+    WaveThumbnail.h
+    Created: 4 Apr 2020 5:47:38pm
+    Author:  Joshua Hodge
+
+  ==============================================================================
+*/
+
+#pragma once
+
+#include <JuceHeader.h>
+#include "PluginProcessor.h"
+
+//==============================================================================
+/*
+*/
+class WaveThumbnail : public Component,
+                      public FileDragAndDropTarget
+{
+public:
+    WaveThumbnail (HelloSamplerAudioProcessor& p);
+    ~WaveThumbnail();
+
+    void paint (Graphics&) override;
+    void resized() override;
+    
+    bool isInterestedInFileDrag (const StringArray& files) override;
+    void filesDropped (const StringArray& files, int x, int y) override;
+
+private:
+    std::vector<float> mAudioPoints;
+    bool mShouldBePainting { false };
+    
+    String mFileName { "" };
+    
+    HelloSamplerAudioProcessor& processor;
+    
+    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (WaveThumbnail)
+};
diff –git a/helloSampler.jucer b/helloSampler.jucer index 227013e..6ef6491 100644
--- a/helloSampler.jucer
+++ b/helloSampler.jucer
@@ -11,6 +11,12 @@
       <FILE id="FlpJkd" name="PluginEditor.cpp" compile="1" resource="0"
             file="Source/PluginEditor.cpp"/>
       <FILE id="PpHnFk" name="PluginEditor.h" compile="0" resource="0" file="Source/PluginEditor.h"/>
+      <FILE id="DAkQPm" name="WaveThumbnail.cpp" compile="1" resource="0"
+            file="Source/WaveThumbnail.cpp"/>
+      <FILE id="BCnNzN" name="WaveThumbnail.h" compile="0" resource="0" file="Source/WaveThumbnail.h"/>
+      <FILE id="D2GmyO" name="ADSRComponent.cpp" compile="1" resource="0"
+            file="Source/ADSRComponent.cpp"/>
+      <FILE id="Hj3zdH" name="ADSRComponent.h" compile="0" resource="0" file="Source/ADSRComponent.h"/>
     </GROUP>
   </MAINGROUP>
   <EXPORTFORMATS>

Diff 0: c5b87db793ed6e6a46eeb17bf4044b6871d924ee to bab32d4bc1a248c886de1941e933a430b85f7b87

index f5f54d5..aaf99d3 100644 — a/Source/[PluginEditor](PluginEditor).cpp
+++ b/Source/PluginEditor.cpp
@@ -17,11 +17,15 @@ HelloSamplerAudioProcessorEditor::HelloSamplerAudioProcessorEditor (HelloSampler
 {
     addAndMakeVisible (mWaveThumbnail);
     addAndMakeVisible (mADSR);
+    
+    startTimerHz (30);
+    
     setSize (600, 400);
 }

 HelloSamplerAudioProcessorEditor::~HelloSamplerAudioProcessorEditor()
 {
+    stopTimer();
 }

 //==============================================================================
@@ -36,5 +40,10 @@ void HelloSamplerAudioProcessorEditor::resized()
     mADSR.setBoundsRelative (0.0f, 0.75f, 1.0f, 0.25f);
 }

+void HelloSamplerAudioProcessorEditor::timerCallback()
+{
+    repaint();
+}
+

diff –git a/Source/[PluginEditor](PluginEditor).h b/Source/[PluginEditor](PluginEditor).h index cfbbb5a..103634c 100644
--- a/Source/PluginEditor.h
+++ b/Source/PluginEditor.h
@@ -18,7 +18,8 @@
 //==============================================================================
 /**
 */
-class HelloSamplerAudioProcessorEditor  : public AudioProcessorEditor
+class HelloSamplerAudioProcessorEditor  : public AudioProcessorEditor,
+                                          public Timer
 {
 public:
     HelloSamplerAudioProcessorEditor (HelloSamplerAudioProcessor&);
@@ -27,6 +28,8 @@ public:
     //==============================================================================
     void paint (Graphics&) override;
     void resized() override;
+    
+    void timerCallback() override;

 private:    
     WaveThumbnail mWaveThumbnail;
diff –git a/Source/[PluginProcessor](PluginProcessor).cpp b/Source/[PluginProcessor](PluginProcessor).cpp index 482282c..f6e9b19 100644
--- a/Source/PluginProcessor.cpp
+++ b/Source/PluginProcessor.cpp
@@ -151,6 +151,20 @@ void HelloSamplerAudioProcessor::processBlock (AudioBuffer<float>& buffer, MidiB
     {
         updateADSR();
     }
+    
+    MidiMessage m;
+    MidiBuffer::Iterator it { midiMessages };
+    int sample;
+    
+    while (it.getNextEvent (m, sample))
+    {
+        if (m.isNoteOn())
+            mIsNotePlayed = true;
+        else if (m.isNoteOff())
+            mIsNotePlayed = false;
+    }
+    
+    mSampleCount = mIsNotePlayed ? mSampleCount += buffer.getNumSamples() : 0;

     mSampler.renderNextBlock (buffer, midiMessages, 0, buffer.getNumSamples());
 }
diff –git a/Source/[PluginProcessor](PluginProcessor).h b/Source/[PluginProcessor](PluginProcessor).h index a89449d..76e868b 100644
--- a/Source/PluginProcessor.h
+++ b/Source/PluginProcessor.h
@@ -66,6 +66,8 @@ public:
     ADSR::Parameters& getADSRParams() { return mADSRParams; }

     AudioProcessorValueTreeState& getValueTree() { return mAPVTS; }
+    std::atomic<bool>& isNotePlayed() { return mIsNotePlayed; }
+    std::atomic<int>& getSampleCount() { return mSampleCount; }

 private:
     Synthesiser mSampler;
@@ -82,6 +84,8 @@ private:
     void valueTreePropertyChanged (ValueTree &treeWhosePropertyHasChanged, const Identifier &property) override;

     std::atomic<bool> mShouldUpdate { false };
+    std::atomic<bool> mIsNotePlayed { false };
+    std::atomic<int> mSampleCount { 0 };

     //==============================================================================
     JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (HelloSamplerAudioProcessor)
diff –git a/Source/[WaveThumbnail](WaveThumbnail).cpp b/Source/[WaveThumbnail](WaveThumbnail).cpp index 14bb904..d50f902 100644
--- a/Source/WaveThumbnail.cpp
+++ b/Source/WaveThumbnail.cpp
@@ -60,6 +60,14 @@ void WaveThumbnail::paint (Graphics& g)
         g.setFont (15.0f);
         auto textBounds = getLocalBounds().reduced (10, 10);
         g.drawFittedText (mFileName, textBounds, Justification::topRight, 1);
+        
+        auto playHeadPosition = jmap<int> (processor.getSampleCount(), 0, processor.getWaveForm().getNumSamples(), 0, getWidth());
+        
+        g.setColour (Colours::white);
+        g.drawLine (playHeadPosition, 0, playHeadPosition, getHeight(), 2.0f);
+        
+        g.setColour (Colours::black.withAlpha (0.2f));
+        g.fillRect (0, 0, playHeadPosition, getHeight());
     }
     else
     {

Diff 0: bab32d4bc1a248c886de1941e933a430b85f7b87 to 3244fcd044ad8724c74da3a3504820fb25de57be

index f6e9b19..f58ce7e 100644 — a/Source/[PluginProcessor](PluginProcessor).cpp
+++ b/Source/PluginProcessor.cpp
@@ -36,7 +36,6 @@ HelloSamplerAudioProcessor::HelloSamplerAudioProcessor()
 HelloSamplerAudioProcessor::~HelloSamplerAudioProcessor()
 {
     mAPVTS.state.removeListener (this);
-    mFormatReader = nullptr;
 }

 //==============================================================================
@@ -203,13 +202,18 @@ void HelloSamplerAudioProcessor::loadFile()
     if (chooser.browseForFileToOpen())
     {
         auto file = chooser.getResult();
-        mFormatReader = mFormatManager.createReaderFor (file);
+        auto reader = mFormatManager.createReaderFor (file);
+        if (reader)
+        {
+            BigInteger range;
+            range.setRange(0, 128, true);
+            mSampler.addSound(new SamplerSound("Sample", *reader, range, 60, 0.1, 0.1, 10.0));
+            delete reader; // reader is no longer needed, the SamplerSound already used it and won't need it further
+        }
+        
     }

-    BigInteger range;
-    range.setRange (0, 128, true);

-    mSampler.addSound (new SamplerSound ("Sample", *mFormatReader, range, 60, 0.1, 0.1, 10.0));
 }

 void HelloSamplerAudioProcessor::loadFile (const String& path)
@@ -217,19 +221,22 @@ void HelloSamplerAudioProcessor::loadFile (const String& path)
     mSampler.clearSounds();

     auto file = File (path);
-    mFormatReader = mFormatManager.createReaderFor (file);
-    
-    auto sampleLength = static_cast<int>(mFormatReader->lengthInSamples);
-    
-    mWaveForm.setSize (1, sampleLength);
-    mFormatReader->read (&mWaveForm, 0, sampleLength, 0, true, false);
-        
-    BigInteger range;
-    range.setRange (0, 128, true);
-    
-    mSampler.addSound (new SamplerSound ("Sample", *mFormatReader, range, 60, 0.1, 0.1, 10.0));
+    auto reader = mFormatManager.createReaderFor (file);
+    if (reader)
+    {
+        auto sampleLength = static_cast<int>(reader->lengthInSamples);
+
+        mWaveForm.setSize(1, sampleLength);
+        reader->read(&mWaveForm, 0, sampleLength, 0, true, false);
+
+        BigInteger range;
+        range.setRange(0, 128, true);
+
+        mSampler.addSound(new SamplerSound("Sample", *reader, range, 60, 0.1, 0.1, 10.0));
+        delete reader; // reader no longer needed, it was already used by the classes that need it
+        updateADSR();
+    }

-    updateADSR();
 }

 void HelloSamplerAudioProcessor::updateADSR()
diff –git a/Source/[PluginProcessor](PluginProcessor).h b/Source/[PluginProcessor](PluginProcessor).h index 76e868b..6ac7c55 100644
--- a/Source/PluginProcessor.h
+++ b/Source/PluginProcessor.h
@@ -77,7 +77,7 @@ private:
     ADSR::Parameters mADSRParams;

     AudioFormatManager mFormatManager;
-    AudioFormatReader* mFormatReader { nullptr };
+    

     AudioProcessorValueTreeState mAPVTS;
     AudioProcessorValueTreeState::ParameterLayout createParameters();
diff –git a/helloSampler.jucer b/helloSampler.jucer index 6ef6491..fcb6446 100644
--- a/helloSampler.jucer
+++ b/helloSampler.jucer
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>

-<JUCERPROJECT id="g3JoRK" name="helloSampler" projectType="audioplug" jucerVersion="5.4.7"
+<JUCERPROJECT id="g3JoRK" name="helloSampler" projectType="audioplug" jucerVersion="6.0.0"
               pluginCharacteristicsValue="pluginIsSynth,pluginWantsMidiIn">
   <MAINGROUP id="yTyWgG" name="helloSampler">
     <GROUP id="{BD93A9F5-4F14-3A8D-2504-0C22B80C3A18}" name="Source">
@@ -42,6 +42,28 @@
         <MODULEPATH id="juce_opengl" path="../../../../../../../Applications/JUCE/modules"/>
       </MODULEPATHS>
     </XCODE_MAC>
+    <VS2019 targetFolder="Builds/VisualStudio2019">
+      <CONFIGURATIONS>
+        <CONFIGURATION isDebug="1" name="Debug"/>
+        <CONFIGURATION isDebug="0" name="Release"/>
+      </CONFIGURATIONS>
+      <MODULEPATHS>
+        <MODULEPATH id="juce_opengl" path="../../juce"/>
+        <MODULEPATH id="juce_gui_extra" path="../../juce"/>
+        <MODULEPATH id="juce_gui_basics" path="../../juce"/>
+        <MODULEPATH id="juce_graphics" path="../../juce"/>
+        <MODULEPATH id="juce_events" path="../../juce"/>
+        <MODULEPATH id="juce_data_structures" path="../../juce"/>
+        <MODULEPATH id="juce_cryptography" path="../../juce"/>
+        <MODULEPATH id="juce_core" path="../../juce"/>
+        <MODULEPATH id="juce_audio_utils" path="../../juce"/>
+        <MODULEPATH id="juce_audio_processors" path="../../juce"/>
+        <MODULEPATH id="juce_audio_plugin_client" path="../../juce"/>
+        <MODULEPATH id="juce_audio_formats" path="../../juce"/>
+        <MODULEPATH id="juce_audio_devices" path="../../juce"/>
+        <MODULEPATH id="juce_audio_basics" path="../../juce"/>
+      </MODULEPATHS>
+    </VS2019>
   </EXPORTFORMATS>
   <MODULES>
     <MODULE id="juce_audio_basics" showAllCode="1" useLocalCopy="0" useGlobalPath="1"/>
@@ -62,6 +84,7 @@
   </MODULES>
   <LIVE_SETTINGS>
     <OSX/>
+    <WINDOWS/>
   </LIVE_SETTINGS>
   <JUCEOPTIONS JUCE_VST3_CAN_REPLACE_VST2="0" JUCE_STRICT_REFCOUNTEDPOINTER="1"/>
 </JUCERPROJECT>

Diff 0: 3244fcd044ad8724c74da3a3504820fb25de57be to 2a4c338005c0a1c771111c265def3cc399e5526f

index f58ce7e..1c13ab3 100644 — a/Source/[PluginProcessor](PluginProcessor).cpp
+++ b/Source/PluginProcessor.cpp
@@ -202,13 +202,13 @@ void HelloSamplerAudioProcessor::loadFile()
     if (chooser.browseForFileToOpen())
     {
         auto file = chooser.getResult();
-        auto reader = mFormatManager.createReaderFor (file);
+        // the reader can be a local variable here since it's not needed by the SamplerSound after this
+        std::unique_ptr<AudioFormatReader> reader{ mFormatManager.createReaderFor(file) };
         if (reader)
         {
             BigInteger range;
             range.setRange(0, 128, true);
             mSampler.addSound(new SamplerSound("Sample", *reader, range, 60, 0.1, 0.1, 10.0));
-            delete reader; // reader is no longer needed, the SamplerSound already used it and won't need it further
         }

     }
@@ -221,7 +221,8 @@ void HelloSamplerAudioProcessor::loadFile (const String& path)
     mSampler.clearSounds();

     auto file = File (path);
-    auto reader = mFormatManager.createReaderFor (file);
+    // the reader can be a local variable here since it's not needed by the other classes after this
+    std::unique_ptr<AudioFormatReader> reader{ mFormatManager.createReaderFor(file) };
     if (reader)
     {
         auto sampleLength = static_cast<int>(reader->lengthInSamples);
@@ -233,7 +234,6 @@ void HelloSamplerAudioProcessor::loadFile (const String& path)
         range.setRange(0, 128, true);

         mSampler.addSound(new SamplerSound("Sample", *reader, range, 60, 0.1, 0.1, 10.0));
-        delete reader; // reader no longer needed, it was already used by the classes that need it
         updateADSR();
     }

Diff 0: 2a4c338005c0a1c771111c265def3cc399e5526f to d4e3bc0cecc12f3a922054564a9eace3c3f4de7c

index 1c13ab3..50718b3 100644 — a/Source/[PluginProcessor](PluginProcessor).cpp
+++ b/Source/PluginProcessor.cpp
@@ -225,20 +225,24 @@ void HelloSamplerAudioProcessor::loadFile (const String& path)
     std::unique_ptr<AudioFormatReader> reader{ mFormatManager.createReaderFor(file) };
     if (reader)
     {
-        auto sampleLength = static_cast<int>(reader->lengthInSamples);
-
-        mWaveForm.setSize(1, sampleLength);
-        reader->read(&mWaveForm, 0, sampleLength, 0, true, false);
-
         BigInteger range;
         range.setRange(0, 128, true);
-
         mSampler.addSound(new SamplerSound("Sample", *reader, range, 60, 0.1, 0.1, 10.0));
         updateADSR();
     }

 }

+AudioBuffer<float>& HelloSamplerAudioProcessor::getWaveForm()
+{
+    // get the last added synth sound as a SamplerSound*
+    auto sound = dynamic_cast<SamplerSound*>(mSampler.getSound(mSampler.getNumSounds() - 1).get());
+    if (sound)
+    {
+        return *sound->getAudioData();
+    }
+}
+
 void HelloSamplerAudioProcessor::updateADSR()
 {
     mShouldUpdate = false;
diff –git a/Source/[PluginProcessor](PluginProcessor).h b/Source/[PluginProcessor](PluginProcessor).h index 6ac7c55..6e116b8 100644
--- a/Source/PluginProcessor.h
+++ b/Source/PluginProcessor.h
@@ -60,7 +60,7 @@ public:
     void loadFile (const String& path);

     int getNumSamplerSounds() { return mSampler.getNumSounds(); }
-    AudioBuffer<float>& getWaveForm() { return mWaveForm; }
+    AudioBuffer<float>& getWaveForm();

     void updateADSR();
     ADSR::Parameters& getADSRParams() { return mADSRParams; }
@@ -72,7 +72,7 @@ public:
 private:
     Synthesiser mSampler;
     const int mNumVoices { 3 };
-    AudioBuffer<float> mWaveForm;
+    

     ADSR::Parameters mADSRParams;

Diff 0: d4e3bc0cecc12f3a922054564a9eace3c3f4de7c to fc81e6cc2e68b4f3072cb1f325ae6f3412e26776

index 50718b3..ccedeb5 100644 — a/Source/[PluginProcessor](PluginProcessor).cpp
+++ b/Source/PluginProcessor.cpp
@@ -241,6 +241,10 @@ AudioBuffer<float>& HelloSamplerAudioProcessor::getWaveForm()
     {
         return *sound->getAudioData();
     }
+    // just in case it somehow happens that the sound doesn't exist or isn't a SamplerSound,
+    // return a static instance of an empty AudioBuffer here...
+    static AudioBuffer<float> dummybuffer;
+    return dummybuffer;
 }

 void HelloSamplerAudioProcessor::updateADSR()

Diff 0: fc81e6cc2e68b4f3072cb1f325ae6f3412e26776 to 43488eac69b59c232e22ba3f24b4ecf33bc7cd89

index aaf99d3..70d8a54 100644 — a/Source/[PluginEditor](PluginEditor).cpp
+++ b/Source/PluginEditor.cpp
@@ -15,8 +15,16 @@
 HelloSamplerAudioProcessorEditor::HelloSamplerAudioProcessorEditor (HelloSamplerAudioProcessor& p)
     : AudioProcessorEditor (&p), mWaveThumbnail (p), mADSR (p), processor (p)
 {
+    auto tapImage = ImageCache::getFromMemory (BinaryData::TAP_png, BinaryData::TAP_pngSize);
+    
+    if (! tapImage.isNull())
+        mImageComponent.setImage (tapImage, RectanglePlacement::stretchToFit);
+    else
+        jassert (! tapImage.isNull());
+    
     addAndMakeVisible (mWaveThumbnail);
     addAndMakeVisible (mADSR);
+    addAndMakeVisible (mImageComponent);

     startTimerHz (30);

@@ -38,6 +46,7 @@ void HelloSamplerAudioProcessorEditor::resized()
 {
     mWaveThumbnail.setBoundsRelative (0.0f, 0.25f, 1.0f, 0.5);
     mADSR.setBoundsRelative (0.0f, 0.75f, 1.0f, 0.25f);
+    mImageComponent.setBoundsRelative (0.0f, 0.0f, 0.5f, 0.25f);
 }

 void HelloSamplerAudioProcessorEditor::timerCallback()
diff –git a/Source/[PluginEditor](PluginEditor).h b/Source/[PluginEditor](PluginEditor).h index 103634c..057172b 100644
--- a/Source/PluginEditor.h
+++ b/Source/PluginEditor.h
@@ -34,6 +34,7 @@ public:
 private:    
     WaveThumbnail mWaveThumbnail;
     ADSRComponent mADSR;
+    ImageComponent mImageComponent;

     HelloSamplerAudioProcessor& processor;
diff –git a/Source/[PluginProcessor](PluginProcessor).cpp b/Source/[PluginProcessor](PluginProcessor).cpp index ccedeb5..f6e9b19 100644
--- a/Source/PluginProcessor.cpp
+++ b/Source/PluginProcessor.cpp
@@ -36,6 +36,7 @@ HelloSamplerAudioProcessor::HelloSamplerAudioProcessor()
 HelloSamplerAudioProcessor::~HelloSamplerAudioProcessor()
 {
     mAPVTS.state.removeListener (this);
+    mFormatReader = nullptr;
 }

 //==============================================================================
@@ -202,18 +203,13 @@ void HelloSamplerAudioProcessor::loadFile()
     if (chooser.browseForFileToOpen())
     {
         auto file = chooser.getResult();
-        // the reader can be a local variable here since it's not needed by the SamplerSound after this
-        std::unique_ptr<AudioFormatReader> reader{ mFormatManager.createReaderFor(file) };
-        if (reader)
-        {
-            BigInteger range;
-            range.setRange(0, 128, true);
-            mSampler.addSound(new SamplerSound("Sample", *reader, range, 60, 0.1, 0.1, 10.0));
-        }
-        
+        mFormatReader = mFormatManager.createReaderFor (file);
     }

+    BigInteger range;
+    range.setRange (0, 128, true);

+    mSampler.addSound (new SamplerSound ("Sample", *mFormatReader, range, 60, 0.1, 0.1, 10.0));
 }

 void HelloSamplerAudioProcessor::loadFile (const String& path)
@@ -221,30 +217,19 @@ void HelloSamplerAudioProcessor::loadFile (const String& path)
     mSampler.clearSounds();

     auto file = File (path);
-    // the reader can be a local variable here since it's not needed by the other classes after this
-    std::unique_ptr<AudioFormatReader> reader{ mFormatManager.createReaderFor(file) };
-    if (reader)
-    {
-        BigInteger range;
-        range.setRange(0, 128, true);
-        mSampler.addSound(new SamplerSound("Sample", *reader, range, 60, 0.1, 0.1, 10.0));
-        updateADSR();
-    }
+    mFormatReader = mFormatManager.createReaderFor (file);

-}
-
-AudioBuffer<float>& HelloSamplerAudioProcessor::getWaveForm()
-{
-    // get the last added synth sound as a SamplerSound*
-    auto sound = dynamic_cast<SamplerSound*>(mSampler.getSound(mSampler.getNumSounds() - 1).get());
-    if (sound)
-    {
-        return *sound->getAudioData();
-    }
-    // just in case it somehow happens that the sound doesn't exist or isn't a SamplerSound,
-    // return a static instance of an empty AudioBuffer here...
-    static AudioBuffer<float> dummybuffer;
-    return dummybuffer;
+    auto sampleLength = static_cast<int>(mFormatReader->lengthInSamples);
+    
+    mWaveForm.setSize (1, sampleLength);
+    mFormatReader->read (&mWaveForm, 0, sampleLength, 0, true, false);
+        
+    BigInteger range;
+    range.setRange (0, 128, true);
+    
+    mSampler.addSound (new SamplerSound ("Sample", *mFormatReader, range, 60, 0.1, 0.1, 10.0));
+    
+    updateADSR();
 }

 void HelloSamplerAudioProcessor::updateADSR()
diff –git a/Source/[PluginProcessor](PluginProcessor).h b/Source/[PluginProcessor](PluginProcessor).h index 6e116b8..76e868b 100644
--- a/Source/PluginProcessor.h
+++ b/Source/PluginProcessor.h
@@ -60,7 +60,7 @@ public:
     void loadFile (const String& path);

     int getNumSamplerSounds() { return mSampler.getNumSounds(); }
-    AudioBuffer<float>& getWaveForm();
+    AudioBuffer<float>& getWaveForm() { return mWaveForm; }

     void updateADSR();
     ADSR::Parameters& getADSRParams() { return mADSRParams; }
@@ -72,12 +72,12 @@ public:
 private:
     Synthesiser mSampler;
     const int mNumVoices { 3 };
-    
+    AudioBuffer<float> mWaveForm;

     ADSR::Parameters mADSRParams;

     AudioFormatManager mFormatManager;
-    
+    AudioFormatReader* mFormatReader { nullptr };

     AudioProcessorValueTreeState mAPVTS;
     AudioProcessorValueTreeState::ParameterLayout createParameters();
diff –git a/helloSampler.jucer b/helloSampler.jucer index fcb6446..093aeae 100644
--- a/helloSampler.jucer
+++ b/helloSampler.jucer
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>

-<JUCERPROJECT id="g3JoRK" name="helloSampler" projectType="audioplug" jucerVersion="6.0.0"
+<JUCERPROJECT id="g3JoRK" name="helloSampler" projectType="audioplug" jucerVersion="5.4.7"
               pluginCharacteristicsValue="pluginIsSynth,pluginWantsMidiIn">
   <MAINGROUP id="yTyWgG" name="helloSampler">
     <GROUP id="{BD93A9F5-4F14-3A8D-2504-0C22B80C3A18}" name="Source">
@@ -18,6 +18,9 @@
             file="Source/ADSRComponent.cpp"/>
       <FILE id="Hj3zdH" name="ADSRComponent.h" compile="0" resource="0" file="Source/ADSRComponent.h"/>
     </GROUP>
+    <GROUP id="{BFC291E8-4FDE-076D-EFCE-7C589FF5E777}" name="Resources">
+      <FILE id="dnuvWI" name="TAP.png" compile="0" resource="1" file="../../../../../Desktop/templatedelay/Resources/TAP.png"/>
+    </GROUP>
   </MAINGROUP>
   <EXPORTFORMATS>
     <XCODE_MAC targetFolder="Builds/MacOSX">
@@ -42,28 +45,6 @@
         <MODULEPATH id="juce_opengl" path="../../../../../../../Applications/JUCE/modules"/>
       </MODULEPATHS>
     </XCODE_MAC>
-    <VS2019 targetFolder="Builds/VisualStudio2019">
-      <CONFIGURATIONS>
-        <CONFIGURATION isDebug="1" name="Debug"/>
-        <CONFIGURATION isDebug="0" name="Release"/>
-      </CONFIGURATIONS>
-      <MODULEPATHS>
-        <MODULEPATH id="juce_opengl" path="../../juce"/>
-        <MODULEPATH id="juce_gui_extra" path="../../juce"/>
-        <MODULEPATH id="juce_gui_basics" path="../../juce"/>
-        <MODULEPATH id="juce_graphics" path="../../juce"/>
-        <MODULEPATH id="juce_events" path="../../juce"/>
-        <MODULEPATH id="juce_data_structures" path="../../juce"/>
-        <MODULEPATH id="juce_cryptography" path="../../juce"/>
-        <MODULEPATH id="juce_core" path="../../juce"/>
-        <MODULEPATH id="juce_audio_utils" path="../../juce"/>
-        <MODULEPATH id="juce_audio_processors" path="../../juce"/>
-        <MODULEPATH id="juce_audio_plugin_client" path="../../juce"/>
-        <MODULEPATH id="juce_audio_formats" path="../../juce"/>
-        <MODULEPATH id="juce_audio_devices" path="../../juce"/>
-        <MODULEPATH id="juce_audio_basics" path="../../juce"/>
-      </MODULEPATHS>
-    </VS2019>
   </EXPORTFORMATS>
   <MODULES>
     <MODULE id="juce_audio_basics" showAllCode="1" useLocalCopy="0" useGlobalPath="1"/>
@@ -84,7 +65,6 @@
   </MODULES>
   <LIVE_SETTINGS>
     <OSX/>
-    <WINDOWS/>
   </LIVE_SETTINGS>
   <JUCEOPTIONS JUCE_VST3_CAN_REPLACE_VST2="0" JUCE_STRICT_REFCOUNTEDPOINTER="1"/>
 </JUCERPROJECT>

Diff 0: 43488eac69b59c232e22ba3f24b4ecf33bc7cd89 to 0d598786f80bafa0ba4f6930e3c29c4de68e2fad

index f6e9b19..ccedeb5 100644 — a/Source/[PluginProcessor](PluginProcessor).cpp
+++ b/Source/PluginProcessor.cpp
@@ -36,7 +36,6 @@ HelloSamplerAudioProcessor::HelloSamplerAudioProcessor()
 HelloSamplerAudioProcessor::~HelloSamplerAudioProcessor()
 {
     mAPVTS.state.removeListener (this);
-    mFormatReader = nullptr;
 }

 //==============================================================================
@@ -203,13 +202,18 @@ void HelloSamplerAudioProcessor::loadFile()
     if (chooser.browseForFileToOpen())
     {
         auto file = chooser.getResult();
-        mFormatReader = mFormatManager.createReaderFor (file);
+        // the reader can be a local variable here since it's not needed by the SamplerSound after this
+        std::unique_ptr<AudioFormatReader> reader{ mFormatManager.createReaderFor(file) };
+        if (reader)
+        {
+            BigInteger range;
+            range.setRange(0, 128, true);
+            mSampler.addSound(new SamplerSound("Sample", *reader, range, 60, 0.1, 0.1, 10.0));
+        }
+        
     }

-    BigInteger range;
-    range.setRange (0, 128, true);

-    mSampler.addSound (new SamplerSound ("Sample", *mFormatReader, range, 60, 0.1, 0.1, 10.0));
 }

 void HelloSamplerAudioProcessor::loadFile (const String& path)
@@ -217,19 +221,30 @@ void HelloSamplerAudioProcessor::loadFile (const String& path)
     mSampler.clearSounds();

     auto file = File (path);
-    mFormatReader = mFormatManager.createReaderFor (file);
-    
-    auto sampleLength = static_cast<int>(mFormatReader->lengthInSamples);
-    
-    mWaveForm.setSize (1, sampleLength);
-    mFormatReader->read (&mWaveForm, 0, sampleLength, 0, true, false);
-        
-    BigInteger range;
-    range.setRange (0, 128, true);
-    
-    mSampler.addSound (new SamplerSound ("Sample", *mFormatReader, range, 60, 0.1, 0.1, 10.0));
+    // the reader can be a local variable here since it's not needed by the other classes after this
+    std::unique_ptr<AudioFormatReader> reader{ mFormatManager.createReaderFor(file) };
+    if (reader)
+    {
+        BigInteger range;
+        range.setRange(0, 128, true);
+        mSampler.addSound(new SamplerSound("Sample", *reader, range, 60, 0.1, 0.1, 10.0));
+        updateADSR();
+    }

-    updateADSR();
+}
+
+AudioBuffer<float>& HelloSamplerAudioProcessor::getWaveForm()
+{
+    // get the last added synth sound as a SamplerSound*
+    auto sound = dynamic_cast<SamplerSound*>(mSampler.getSound(mSampler.getNumSounds() - 1).get());
+    if (sound)
+    {
+        return *sound->getAudioData();
+    }
+    // just in case it somehow happens that the sound doesn't exist or isn't a SamplerSound,
+    // return a static instance of an empty AudioBuffer here...
+    static AudioBuffer<float> dummybuffer;
+    return dummybuffer;
 }

 void HelloSamplerAudioProcessor::updateADSR()
diff –git a/Source/[PluginProcessor](PluginProcessor).h b/Source/[PluginProcessor](PluginProcessor).h index 76e868b..6e116b8 100644
--- a/Source/PluginProcessor.h
+++ b/Source/PluginProcessor.h
@@ -60,7 +60,7 @@ public:
     void loadFile (const String& path);

     int getNumSamplerSounds() { return mSampler.getNumSounds(); }
-    AudioBuffer<float>& getWaveForm() { return mWaveForm; }
+    AudioBuffer<float>& getWaveForm();

     void updateADSR();
     ADSR::Parameters& getADSRParams() { return mADSRParams; }
@@ -72,12 +72,12 @@ public:
 private:
     Synthesiser mSampler;
     const int mNumVoices { 3 };
-    AudioBuffer<float> mWaveForm;
+    

     ADSR::Parameters mADSRParams;

     AudioFormatManager mFormatManager;
-    AudioFormatReader* mFormatReader { nullptr };
+    

     AudioProcessorValueTreeState mAPVTS;
     AudioProcessorValueTreeState::ParameterLayout createParameters();
diff –git a/helloSampler.jucer b/helloSampler.jucer index 093aeae..b60ffdd 100644
--- a/helloSampler.jucer
+++ b/helloSampler.jucer
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>

-<JUCERPROJECT id="g3JoRK" name="helloSampler" projectType="audioplug" jucerVersion="5.4.7"
+<JUCERPROJECT id="g3JoRK" name="helloSampler" projectType="audioplug" jucerVersion="6.0.0"
               pluginCharacteristicsValue="pluginIsSynth,pluginWantsMidiIn">
   <MAINGROUP id="yTyWgG" name="helloSampler">
     <GROUP id="{BD93A9F5-4F14-3A8D-2504-0C22B80C3A18}" name="Source">
@@ -45,6 +45,28 @@
         <MODULEPATH id="juce_opengl" path="../../../../../../../Applications/JUCE/modules"/>
       </MODULEPATHS>
     </XCODE_MAC>
+    <VS2019 targetFolder="Builds/VisualStudio2019">
+      <CONFIGURATIONS>
+        <CONFIGURATION isDebug="1" name="Debug"/>
+        <CONFIGURATION isDebug="0" name="Release"/>
+      </CONFIGURATIONS>
+      <MODULEPATHS>
+        <MODULEPATH id="juce_opengl" path="../../juce"/>
+        <MODULEPATH id="juce_gui_extra" path="../../juce"/>
+        <MODULEPATH id="juce_gui_basics" path="../../juce"/>
+        <MODULEPATH id="juce_graphics" path="../../juce"/>
+        <MODULEPATH id="juce_events" path="../../juce"/>
+        <MODULEPATH id="juce_data_structures" path="../../juce"/>
+        <MODULEPATH id="juce_cryptography" path="../../juce"/>
+        <MODULEPATH id="juce_core" path="../../juce"/>
+        <MODULEPATH id="juce_audio_utils" path="../../juce"/>
+        <MODULEPATH id="juce_audio_processors" path="../../juce"/>
+        <MODULEPATH id="juce_audio_plugin_client" path="../../juce"/>
+        <MODULEPATH id="juce_audio_formats" path="../../juce"/>
+        <MODULEPATH id="juce_audio_devices" path="../../juce"/>
+        <MODULEPATH id="juce_audio_basics" path="../../juce"/>
+      </MODULEPATHS>
+    </VS2019>
   </EXPORTFORMATS>
   <MODULES>
     <MODULE id="juce_audio_basics" showAllCode="1" useLocalCopy="0" useGlobalPath="1"/>
@@ -65,6 +87,7 @@
   </MODULES>
   <LIVE_SETTINGS>
     <OSX/>
+    <WINDOWS/>
   </LIVE_SETTINGS>
   <JUCEOPTIONS JUCE_VST3_CAN_REPLACE_VST2="0" JUCE_STRICT_REFCOUNTEDPOINTER="1"/>
 </JUCERPROJECT>