From [github](https://github.com/TheAudioProgrammer/helloSampler)

Diff 0: 0268fe68eb3bfe0084e9fe7168195d64f8acb3d3 to f960ba20b9a81d2a8615d60b1e1425b9ef94edcc

index 723fd44..f132eed 100644 --- a/Source/PluginEditor.cpp
```diff +++ 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.h b/Source/PluginEditor.h index 6977b1a..9f76bcf 100644
```diff --- 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.cpp b/Source/PluginProcessor.cpp index bf74960..1edaab0 100644
```diff --- 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.h b/Source/PluginProcessor.h index b7dbe43..b16ab4c 100644
```diff --- 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.cpp
```diff +++ 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 (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.h b/Source/PluginEditor.h index 9f76bcf..e28d869 100644
```diff --- a/Source/PluginEditor.h +++ b/Source/PluginEditor.h @@ -32,6 +32,8 @@ public: private: TextButton mLoadButton { "Load" }; + std::vector mAudioPoints; + bool mShouldBePainting { false }; HelloSamplerAudioProcessor& processor; ```
diff --git a/Source/PluginProcessor.cpp b/Source/PluginProcessor.cpp index 1edaab0..bf97e42 100644
```diff --- 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(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.h b/Source/PluginProcessor.h index b16ab4c..c8ef3b8 100644
```diff --- a/Source/PluginProcessor.h +++ b/Source/PluginProcessor.h @@ -59,10 +59,12 @@ public: void loadFile (const String& path); int getNumSamplerSounds() { return mSampler.getNumSounds(); } + AudioBuffer& getWaveForm() { return mWaveForm; } private: Synthesiser mSampler; const int mNumVoices { 3 }; + AudioBuffer mWaveForm; AudioFormatManager mFormatManager; AudioFormatReader* mFormatReader { nullptr }; ```

Diff 0: f61194d0081a7399c45f3778d267bfabfff8958b to 7d6d192f9a547bb35df07edadc9ea9ffb888429d

new file mode 100644 index 0000000..6a7eb89
```diff --- /dev/null +++ b/Source/ADSRComponent.cpp @@ -0,0 +1,90 @@ +/* + ============================================================================== + + ADSRComponent.cpp + Created: 14 Mar 2020 2:52:49pm + Author: Joshua Hodge + + ============================================================================== +*/ + +#include +#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.h b/Source/ADSRComponent.h new file mode 100644
```diff 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 +#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.cpp b/Source/MySampler.cpp new file mode 100644
```diff 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.h b/Source/MySampler.h new file mode 100644
```diff 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 + +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& 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.cpp b/Source/PluginEditor.cpp index a8ac4ce..f726008 100644
```diff --- 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.h b/Source/PluginEditor.h index e28d869..98630cc 100644
```diff --- a/Source/PluginEditor.h +++ b/Source/PluginEditor.h @@ -35,6 +35,9 @@ private: std::vector 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.cpp
```diff +++ 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.h b/Source/PluginEditor.h index 98630cc..14872d2 100644
```diff --- 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.cpp b/Source/PluginProcessor.cpp index bf97e42..8341563 100644
```diff --- a/Source/PluginProcessor.cpp +++ b/Source/PluginProcessor.cpp @@ -140,6 +140,8 @@ void HelloSamplerAudioProcessor::processBlock (AudioBuffer& 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.h b/Source/PluginProcessor.h index c8ef3b8..fc2283b 100644
```diff --- a/Source/PluginProcessor.h +++ b/Source/PluginProcessor.h @@ -60,6 +60,13 @@ public: int getNumSamplerSounds() { return mSampler.getNumSounds(); } AudioBuffer& 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.cpp
```diff +++ 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.cpp b/Source/PluginProcessor.cpp index 8341563..a220897 100644
```diff --- 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& 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(mSampler.getSound(i).get())) + { + sound->setEnvelopeParameters (mADSRParams); + } + } } //============================================================================== ```
diff --git a/Source/PluginProcessor.h b/Source/PluginProcessor.h index fc2283b..dc92e83 100644
```diff --- a/Source/PluginProcessor.h +++ b/Source/PluginProcessor.h @@ -61,18 +61,17 @@ public: int getNumSamplerSounds() { return mSampler.getNumSounds(); } AudioBuffer& 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 mWaveForm; + ADSR::Parameters mADSRParams; + AudioFormatManager mFormatManager; AudioFormatReader* mFormatReader { nullptr }; ```

Diff 0: a5bcea55e10d3ca14893c60ffe1ef6b2633a6009 to 4f1cc61b0c309abd6336c9599faca10ca020d024

index 0f905df..039a547 100644 --- a/Source/PluginEditor.cpp
```diff +++ 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(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(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(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(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.h b/Source/PluginEditor.h index 14872d2..e4ae2b6 100644
```diff --- 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 mAttackAttachment; + std::unique_ptr mDecayAttachment; + std::unique_ptr mSustainAttachment; + std::unique_ptr mReleaseAttachment; + HelloSamplerAudioProcessor& processor; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (HelloSamplerAudioProcessorEditor) ```
diff --git a/Source/PluginProcessor.cpp b/Source/PluginProcessor.cpp index a220897..482282c 100644
```diff --- 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& 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(mSampler.getSound(i).get())) @@ -220,6 +236,23 @@ void HelloSamplerAudioProcessor::updateADSR() } } +AudioProcessorValueTreeState::ParameterLayout HelloSamplerAudioProcessor::createParameters() +{ + std::vector> params; + + params.push_back (std::make_unique("ATTACK", "Attack", 0.0f, 5.0f, 0.0f)); + params.push_back (std::make_unique("DECAY", "Decay", 0.0f, 5.0f, 2.0f)); + params.push_back (std::make_unique("SUSTAIN", "Sustain", 0.0f, 1.0f, 1.0f)); + params.push_back (std::make_unique("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.h b/Source/PluginProcessor.h index dc92e83..a89449d 100644
```diff --- 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& 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 mShouldUpdate { false }; + //============================================================================== JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (HelloSamplerAudioProcessor) }; ```

Diff 0: 4f1cc61b0c309abd6336c9599faca10ca020d024 to c5b87db793ed6e6a46eeb17bf4044b6871d924ee

index 6a7eb89..3f5085d 100644 --- a/Source/ADSRComponent.cpp
```diff +++ 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(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(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(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(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.h b/Source/ADSRComponent.h index 66ea725..daf48ba 100644
```diff --- 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 #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 mAttackAttachment; + std::unique_ptr mDecayAttachment; + std::unique_ptr mSustainAttachment; + std::unique_ptr mReleaseAttachment; HelloSamplerAudioProcessor& processor; - + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ADSRComponent) }; ```
diff --git a/Source/MySampler.cpp b/Source/MySampler.cpp deleted file mode 100644
```diff 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.h b/Source/MySampler.h deleted file mode 100644
```diff 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 - -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& 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.cpp b/Source/PluginEditor.cpp index 039a547..f5f54d5 100644
```diff --- 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(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(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(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(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 (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.h b/Source/PluginEditor.h index e4ae2b6..cfbbb5a 100644
```diff --- a/Source/PluginEditor.h +++ b/Source/PluginEditor.h @@ -12,12 +12,13 @@ #include #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 mAudioPoints; - bool mShouldBePainting { false }; - - Slider mAttackSlider, mDecaySlider, mSustainSlider, mReleaseSlider; - Label mAttackLabel, mDecayLabel, mSustainLabel, mReleaseLabel; - - std::unique_ptr mAttackAttachment; - std::unique_ptr mDecayAttachment; - std::unique_ptr mSustainAttachment; - std::unique_ptr mReleaseAttachment; +private: + WaveThumbnail mWaveThumbnail; + ADSRComponent mADSR; HelloSamplerAudioProcessor& processor; ```
diff --git a/Source/WaveThumbnail.cpp b/Source/WaveThumbnail.cpp new file mode 100644
```diff 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 +#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 (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); + mFileName = myFile->getFileNameWithoutExtension(); + + processor.loadFile (file); + } + } + + repaint(); +} ```
diff --git a/Source/WaveThumbnail.h b/Source/WaveThumbnail.h new file mode 100644
```diff 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 +#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 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
```diff --- a/helloSampler.jucer +++ b/helloSampler.jucer @@ -11,6 +11,12 @@ + + + + ```

Diff 0: c5b87db793ed6e6a46eeb17bf4044b6871d924ee to bab32d4bc1a248c886de1941e933a430b85f7b87

index f5f54d5..aaf99d3 100644 --- a/Source/PluginEditor.cpp
```diff +++ 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.h b/Source/PluginEditor.h index cfbbb5a..103634c 100644
```diff --- 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.cpp b/Source/PluginProcessor.cpp index 482282c..f6e9b19 100644
```diff --- a/Source/PluginProcessor.cpp +++ b/Source/PluginProcessor.cpp @@ -151,6 +151,20 @@ void HelloSamplerAudioProcessor::processBlock (AudioBuffer& 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.h b/Source/PluginProcessor.h index a89449d..76e868b 100644
```diff --- a/Source/PluginProcessor.h +++ b/Source/PluginProcessor.h @@ -66,6 +66,8 @@ public: ADSR::Parameters& getADSRParams() { return mADSRParams; } AudioProcessorValueTreeState& getValueTree() { return mAPVTS; } + std::atomic& isNotePlayed() { return mIsNotePlayed; } + std::atomic& getSampleCount() { return mSampleCount; } private: Synthesiser mSampler; @@ -82,6 +84,8 @@ private: void valueTreePropertyChanged (ValueTree &treeWhosePropertyHasChanged, const Identifier &property) override; std::atomic mShouldUpdate { false }; + std::atomic mIsNotePlayed { false }; + std::atomic mSampleCount { 0 }; //============================================================================== JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (HelloSamplerAudioProcessor) ```
diff --git a/Source/WaveThumbnail.cpp b/Source/WaveThumbnail.cpp index 14bb904..d50f902 100644
```diff --- 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 (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.cpp
```diff +++ 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(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(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.h b/Source/PluginProcessor.h index 76e868b..6ac7c55 100644
```diff --- 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
```diff --- a/helloSampler.jucer +++ b/helloSampler.jucer @@ -1,6 +1,6 @@ - @@ -42,6 +42,28 @@ + + + + + + + + + + + + + + + + + + + + + +
@@ -62,6 +84,7 @@ + ```

Diff 0: 3244fcd044ad8724c74da3a3504820fb25de57be to 2a4c338005c0a1c771111c265def3cc399e5526f

index f58ce7e..1c13ab3 100644 --- a/Source/PluginProcessor.cpp
```diff +++ 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 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 reader{ mFormatManager.createReaderFor(file) }; if (reader) { auto sampleLength = static_cast(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.cpp
```diff +++ b/Source/PluginProcessor.cpp @@ -225,20 +225,24 @@ void HelloSamplerAudioProcessor::loadFile (const String& path) std::unique_ptr reader{ mFormatManager.createReaderFor(file) }; if (reader) { - auto sampleLength = static_cast(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& HelloSamplerAudioProcessor::getWaveForm() +{ + // get the last added synth sound as a SamplerSound* + auto sound = dynamic_cast(mSampler.getSound(mSampler.getNumSounds() - 1).get()); + if (sound) + { + return *sound->getAudioData(); + } +} + void HelloSamplerAudioProcessor::updateADSR() { mShouldUpdate = false; ```
diff --git a/Source/PluginProcessor.h b/Source/PluginProcessor.h index 6ac7c55..6e116b8 100644
```diff --- a/Source/PluginProcessor.h +++ b/Source/PluginProcessor.h @@ -60,7 +60,7 @@ public: void loadFile (const String& path); int getNumSamplerSounds() { return mSampler.getNumSounds(); } - AudioBuffer& getWaveForm() { return mWaveForm; } + AudioBuffer& getWaveForm(); void updateADSR(); ADSR::Parameters& getADSRParams() { return mADSRParams; } @@ -72,7 +72,7 @@ public: private: Synthesiser mSampler; const int mNumVoices { 3 }; - AudioBuffer mWaveForm; + ADSR::Parameters mADSRParams; ```

Diff 0: d4e3bc0cecc12f3a922054564a9eace3c3f4de7c to fc81e6cc2e68b4f3072cb1f325ae6f3412e26776

index 50718b3..ccedeb5 100644 --- a/Source/PluginProcessor.cpp
```diff +++ b/Source/PluginProcessor.cpp @@ -241,6 +241,10 @@ AudioBuffer& 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 dummybuffer; + return dummybuffer; } void HelloSamplerAudioProcessor::updateADSR() ```

Diff 0: fc81e6cc2e68b4f3072cb1f325ae6f3412e26776 to 43488eac69b59c232e22ba3f24b4ecf33bc7cd89

index aaf99d3..70d8a54 100644 --- a/Source/PluginEditor.cpp
```diff +++ 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.h b/Source/PluginEditor.h index 103634c..057172b 100644
```diff --- 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.cpp b/Source/PluginProcessor.cpp index ccedeb5..f6e9b19 100644
```diff --- 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 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 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& HelloSamplerAudioProcessor::getWaveForm() -{ - // get the last added synth sound as a SamplerSound* - auto sound = dynamic_cast(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 dummybuffer; - return dummybuffer; + auto sampleLength = static_cast(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.h b/Source/PluginProcessor.h index 6e116b8..76e868b 100644
```diff --- a/Source/PluginProcessor.h +++ b/Source/PluginProcessor.h @@ -60,7 +60,7 @@ public: void loadFile (const String& path); int getNumSamplerSounds() { return mSampler.getNumSounds(); } - AudioBuffer& getWaveForm(); + AudioBuffer& getWaveForm() { return mWaveForm; } void updateADSR(); ADSR::Parameters& getADSRParams() { return mADSRParams; } @@ -72,12 +72,12 @@ public: private: Synthesiser mSampler; const int mNumVoices { 3 }; - + AudioBuffer 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
```diff --- a/helloSampler.jucer +++ b/helloSampler.jucer @@ -1,6 +1,6 @@ - @@ -18,6 +18,9 @@ file="Source/ADSRComponent.cpp"/> + + + @@ -42,28 +45,6 @@ - - - - - - - - - - - - - - - - - - - - - - @@ -84,7 +65,6 @@ - ```

Diff 0: 43488eac69b59c232e22ba3f24b4ecf33bc7cd89 to 0d598786f80bafa0ba4f6930e3c29c4de68e2fad

index f6e9b19..ccedeb5 100644 --- a/Source/PluginProcessor.cpp
```diff +++ 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 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(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 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& HelloSamplerAudioProcessor::getWaveForm() +{ + // get the last added synth sound as a SamplerSound* + auto sound = dynamic_cast(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 dummybuffer; + return dummybuffer; } void HelloSamplerAudioProcessor::updateADSR() ```
diff --git a/Source/PluginProcessor.h b/Source/PluginProcessor.h index 76e868b..6e116b8 100644
```diff --- a/Source/PluginProcessor.h +++ b/Source/PluginProcessor.h @@ -60,7 +60,7 @@ public: void loadFile (const String& path); int getNumSamplerSounds() { return mSampler.getNumSounds(); } - AudioBuffer& getWaveForm() { return mWaveForm; } + AudioBuffer& getWaveForm(); void updateADSR(); ADSR::Parameters& getADSRParams() { return mADSRParams; } @@ -72,12 +72,12 @@ public: private: Synthesiser mSampler; const int mNumVoices { 3 }; - AudioBuffer 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
```diff --- a/helloSampler.jucer +++ b/helloSampler.jucer @@ -1,6 +1,6 @@ - @@ -45,6 +45,28 @@ + + + + + + + + + + + + + + + + + + + + + + @@ -65,6 +87,7 @@ + ```