├── Source
├── GUIComponents
│ ├── .DS_Store
│ ├── CustomLookAndFeel.h
│ ├── CustomSlider.h
│ ├── CustomSlider.cpp
│ ├── FilterResponseDisplay.h
│ ├── FilterResponseDisplay.cpp
│ └── CustomLookAndFeel.cpp
├── AudioDSPComponents
│ ├── .DS_Store
│ ├── AudioFilter.cpp
│ ├── VAOnePoleFilter.h
│ ├── AudioFilter.h
│ └── VAOnePoleFilter.cpp
├── PluginEditor.h
├── Parameters
│ ├── CustomAudioParameter.h
│ └── CustomAudioParameter.cpp
├── PluginProcessor.h
├── PluginEditor.cpp
└── PluginProcessor.cpp
├── Builds
└── MacOSX
│ ├── RecentFilesMenuTemplate.nib
│ └── Info.plist
├── JuceLibraryCode
├── modules
│ ├── juce_core
│ │ └── juce_core.h
│ ├── juce_events
│ │ └── juce_events.h
│ ├── juce_opengl
│ │ └── juce_opengl.h
│ ├── juce_video
│ │ └── juce_video.h
│ ├── juce_graphics
│ │ └── juce_graphics.h
│ ├── juce_gui_extra
│ │ └── juce_gui_extra.h
│ ├── juce_gui_basics
│ │ └── juce_gui_basics.h
│ ├── juce_audio_basics
│ │ └── juce_audio_basics.h
│ ├── juce_cryptography
│ │ └── juce_cryptography.h
│ ├── juce_audio_devices
│ │ └── juce_audio_devices.h
│ ├── juce_audio_formats
│ │ └── juce_audio_formats.h
│ ├── juce_audio_processors
│ │ └── juce_audio_processors.h
│ ├── juce_data_structures
│ │ └── juce_data_structures.h
│ └── juce_audio_plugin_client
│ │ └── juce_audio_plugin_client.h
├── ReadMe.txt
├── JuceHeader.h
└── AppConfig.h
├── README.md
└── FilterGuiDemo.jucer
/Source/GUIComponents/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JoshMarler/filter-gui-demo/HEAD/Source/GUIComponents/.DS_Store
--------------------------------------------------------------------------------
/Source/AudioDSPComponents/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JoshMarler/filter-gui-demo/HEAD/Source/AudioDSPComponents/.DS_Store
--------------------------------------------------------------------------------
/Builds/MacOSX/RecentFilesMenuTemplate.nib:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JoshMarler/filter-gui-demo/HEAD/Builds/MacOSX/RecentFilesMenuTemplate.nib
--------------------------------------------------------------------------------
/JuceLibraryCode/modules/juce_core/juce_core.h:
--------------------------------------------------------------------------------
1 | // This is an auto-generated file to redirect any included
2 | // module headers to the correct external folder.
3 |
4 | #include "../../../../../SDK/JUCE/modules/juce_core/juce_core.h"
5 |
--------------------------------------------------------------------------------
/JuceLibraryCode/modules/juce_events/juce_events.h:
--------------------------------------------------------------------------------
1 | // This is an auto-generated file to redirect any included
2 | // module headers to the correct external folder.
3 |
4 | #include "../../../../../SDK/JUCE/modules/juce_events/juce_events.h"
5 |
--------------------------------------------------------------------------------
/JuceLibraryCode/modules/juce_opengl/juce_opengl.h:
--------------------------------------------------------------------------------
1 | // This is an auto-generated file to redirect any included
2 | // module headers to the correct external folder.
3 |
4 | #include "../../../../../SDK/JUCE/modules/juce_opengl/juce_opengl.h"
5 |
--------------------------------------------------------------------------------
/JuceLibraryCode/modules/juce_video/juce_video.h:
--------------------------------------------------------------------------------
1 | // This is an auto-generated file to redirect any included
2 | // module headers to the correct external folder.
3 |
4 | #include "../../../../../SDK/JUCE/modules/juce_video/juce_video.h"
5 |
--------------------------------------------------------------------------------
/JuceLibraryCode/modules/juce_graphics/juce_graphics.h:
--------------------------------------------------------------------------------
1 | // This is an auto-generated file to redirect any included
2 | // module headers to the correct external folder.
3 |
4 | #include "../../../../../SDK/JUCE/modules/juce_graphics/juce_graphics.h"
5 |
--------------------------------------------------------------------------------
/JuceLibraryCode/modules/juce_gui_extra/juce_gui_extra.h:
--------------------------------------------------------------------------------
1 | // This is an auto-generated file to redirect any included
2 | // module headers to the correct external folder.
3 |
4 | #include "../../../../../SDK/JUCE/modules/juce_gui_extra/juce_gui_extra.h"
5 |
--------------------------------------------------------------------------------
/JuceLibraryCode/modules/juce_gui_basics/juce_gui_basics.h:
--------------------------------------------------------------------------------
1 | // This is an auto-generated file to redirect any included
2 | // module headers to the correct external folder.
3 |
4 | #include "../../../../../SDK/JUCE/modules/juce_gui_basics/juce_gui_basics.h"
5 |
--------------------------------------------------------------------------------
/JuceLibraryCode/modules/juce_audio_basics/juce_audio_basics.h:
--------------------------------------------------------------------------------
1 | // This is an auto-generated file to redirect any included
2 | // module headers to the correct external folder.
3 |
4 | #include "../../../../../SDK/JUCE/modules/juce_audio_basics/juce_audio_basics.h"
5 |
--------------------------------------------------------------------------------
/JuceLibraryCode/modules/juce_cryptography/juce_cryptography.h:
--------------------------------------------------------------------------------
1 | // This is an auto-generated file to redirect any included
2 | // module headers to the correct external folder.
3 |
4 | #include "../../../../../SDK/JUCE/modules/juce_cryptography/juce_cryptography.h"
5 |
--------------------------------------------------------------------------------
/JuceLibraryCode/modules/juce_audio_devices/juce_audio_devices.h:
--------------------------------------------------------------------------------
1 | // This is an auto-generated file to redirect any included
2 | // module headers to the correct external folder.
3 |
4 | #include "../../../../../SDK/JUCE/modules/juce_audio_devices/juce_audio_devices.h"
5 |
--------------------------------------------------------------------------------
/JuceLibraryCode/modules/juce_audio_formats/juce_audio_formats.h:
--------------------------------------------------------------------------------
1 | // This is an auto-generated file to redirect any included
2 | // module headers to the correct external folder.
3 |
4 | #include "../../../../../SDK/JUCE/modules/juce_audio_formats/juce_audio_formats.h"
5 |
--------------------------------------------------------------------------------
/JuceLibraryCode/modules/juce_audio_processors/juce_audio_processors.h:
--------------------------------------------------------------------------------
1 | // This is an auto-generated file to redirect any included
2 | // module headers to the correct external folder.
3 |
4 | #include "../../../../../SDK/JUCE/modules/juce_audio_processors/juce_audio_processors.h"
5 |
--------------------------------------------------------------------------------
/JuceLibraryCode/modules/juce_data_structures/juce_data_structures.h:
--------------------------------------------------------------------------------
1 | // This is an auto-generated file to redirect any included
2 | // module headers to the correct external folder.
3 |
4 | #include "../../../../../SDK/JUCE/modules/juce_data_structures/juce_data_structures.h"
5 |
--------------------------------------------------------------------------------
/JuceLibraryCode/modules/juce_audio_plugin_client/juce_audio_plugin_client.h:
--------------------------------------------------------------------------------
1 | // This is an auto-generated file to redirect any included
2 | // module headers to the correct external folder.
3 |
4 | #include "../../../../../SDK/JUCE/modules/juce_audio_plugin_client/juce_audio_plugin_client.h"
5 |
--------------------------------------------------------------------------------
/JuceLibraryCode/ReadMe.txt:
--------------------------------------------------------------------------------
1 |
2 | Important Note!!
3 | ================
4 |
5 | The purpose of this folder is to contain files that are auto-generated by the Introjucer,
6 | and ALL files in this folder will be mercilessly DELETED and completely re-written whenever
7 | the Introjucer saves your project.
8 |
9 | Therefore, it's a bad idea to make any manual changes to the files in here, or to
10 | put any of your own files in here if you don't want to lose them. (Of course you may choose
11 | to add the folder's contents to your version-control system so that you can re-merge your own
12 | modifications after the Introjucer has saved its changes).
13 |
--------------------------------------------------------------------------------
/Source/GUIComponents/CustomLookAndFeel.h:
--------------------------------------------------------------------------------
1 | /*
2 | ==============================================================================
3 |
4 | CustomLookAndFeel.h
5 | Created: 19 Sep 2014 7:23:32pm
6 | Author: Joshua Marler
7 |
8 | ==============================================================================
9 | */
10 |
11 | #ifndef CustomLookAndFeel_H_INCLUDED
12 | #define CustomLookAndFeel_H_INCLUDED
13 |
14 | #include "../JuceLibraryCode/JuceHeader.h"
15 |
16 |
17 | class CustomLookAndFeel : public LookAndFeel_V3
18 |
19 | {
20 | public:
21 | void drawRotarySlider (Graphics&, int x, int y, int width, int height,
22 | float sliderPosProportional, float rotaryStartAngle, float rotaryEndAngle,
23 | Slider&) override;
24 | };
25 |
26 |
27 |
28 | #endif // CustomLookAndFeel_H_INCLUDED
29 |
--------------------------------------------------------------------------------
/Source/GUIComponents/CustomSlider.h:
--------------------------------------------------------------------------------
1 | /*
2 | ==============================================================================
3 |
4 | ParameterSlider.h
5 | Created: 17 Feb 2016 9:58:49pm
6 | Author: Joshua Marler
7 |
8 | ==============================================================================
9 | */
10 | #include "../JuceLibraryCode/JuceHeader.h"
11 |
12 | #ifndef CUSTOMSLIDER_H_INCLUDED
13 | #define CUSTOMSLIDER_H_INCLUDED
14 |
15 | class CustomSlider : public Slider,
16 | private Timer
17 | {
18 | public:
19 | CustomSlider(AudioProcessorParameter& p);
20 |
21 | void valueChanged() override;
22 | void timerCallback() override;
23 |
24 | void startedDragging() override;
25 | void stoppedDragging() override;
26 |
27 | double getValueFromText (const String& text) override;
28 | String getTextFromValue (double value) override;
29 |
30 | void updateSliderPos();
31 |
32 | private:
33 |
34 | AudioProcessorParameter& param;
35 | JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CustomSlider)
36 | };
37 |
38 |
39 |
40 | #endif // CUSTOMSLIDER_H_INCLUDED
41 |
--------------------------------------------------------------------------------
/Source/GUIComponents/CustomSlider.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | ==============================================================================
3 |
4 | ParameterSlider.cpp
5 | Created: 17 Feb 2016 9:58:49pm
6 | Author: Joshua Marler
7 |
8 | ==============================================================================
9 | */
10 |
11 | #include "CustomSlider.h"
12 |
13 | CustomSlider::CustomSlider (AudioProcessorParameter& p)
14 | : Slider (p.getName (256)), param (p)
15 | {
16 | startTimerHz (30);
17 | updateSliderPos();
18 | }
19 |
20 | void CustomSlider::valueChanged()
21 | {
22 |
23 | float value = (float) Slider::getValue();
24 | param.setValueNotifyingHost(value);
25 | }
26 |
27 | void CustomSlider::timerCallback()
28 | {
29 | updateSliderPos();
30 | }
31 |
32 | void CustomSlider::startedDragging()
33 | {
34 | param.beginChangeGesture();
35 | }
36 | void CustomSlider::stoppedDragging()
37 | {
38 | param.endChangeGesture();
39 | }
40 |
41 | double CustomSlider::getValueFromText (const String& text)
42 | {
43 | return param.getValueForText (text);
44 | }
45 |
46 | String CustomSlider::getTextFromValue (double value)
47 | {
48 |
49 | return param.getText ((float) value, 1024);
50 | }
51 |
52 | void CustomSlider::updateSliderPos()
53 | {
54 | float newValue = param.getValue();
55 |
56 | if (newValue != (float) Slider::getValue() && ! isMouseButtonDown())
57 | Slider::setValue (newValue);
58 | }
--------------------------------------------------------------------------------
/Source/AudioDSPComponents/AudioFilter.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | ==============================================================================
3 |
4 | AudioFilter.cpp
5 | Created: 25 Jul 2015 10:05:58am
6 | Author: Joshua Marler
7 |
8 | ==============================================================================
9 | */
10 |
11 | #include "AudioFilter.h"
12 |
13 | AudioFilter::AudioFilter()
14 | {
15 | filterType = LowPass;
16 | }
17 |
18 | AudioFilter::~AudioFilter()
19 | {
20 |
21 | }
22 |
23 | void AudioFilter::setCutoff(float newCutoffFrequency)
24 | {
25 | cutoffFrequency = newCutoffFrequency;
26 | }
27 |
28 |
29 | float AudioFilter::getCutoff() const
30 | {
31 | return cutoffFrequency;
32 | }
33 |
34 | void AudioFilter::setGain(float newGain)
35 | {
36 | filterGain = newGain;
37 | }
38 |
39 | float AudioFilter::getGain() const
40 | {
41 | return filterGain;
42 | }
43 |
44 | void AudioFilter::setQFactor(float newQFactor)
45 | {
46 | qFactor = newQFactor;
47 | }
48 |
49 | float AudioFilter::getQFactor() const
50 | {
51 | return qFactor;
52 | }
53 |
54 | void AudioFilter::setFilterType(int type)
55 | {
56 | filterType = type;
57 | }
58 |
59 | int AudioFilter::getFilterType() const
60 | {
61 | return filterType;
62 | }
63 |
64 | //Default filter response implementations
65 | float AudioFilter::getMagnitudeResponse(float freq) const
66 | {
67 | return 0.0;
68 | }
69 |
70 | float AudioFilter::getPhaseResponse(float freq) const
71 | {
72 | return 0.0;
73 | }
74 |
--------------------------------------------------------------------------------
/Builds/MacOSX/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | CFBundleExecutable
7 | ${EXECUTABLE_NAME}
8 | CFBundleIconFile
9 |
10 | CFBundleIdentifier
11 | com.RudeAudio.FilterGuiDemo
12 | CFBundleName
13 | FilterGuiDemo
14 | CFBundlePackageType
15 | TDMw
16 | CFBundleSignature
17 | PTul
18 | CFBundleShortVersionString
19 | 1.0.0
20 | CFBundleVersion
21 | 1.0.0
22 | NSHumanReadableCopyright
23 | RudeAudio
24 | NSHighResolutionCapable
25 |
26 | AudioComponents
27 |
28 |
29 | name
30 | RudeAudio: FilterGuiDemo
31 | description
32 | FilterGuiDemo
33 | factoryFunction
34 | FilterGuiDemoAUFactory
35 | manufacturer
36 | RUDE
37 | type
38 | aufx
39 | subtype
40 | RFil
41 | version
42 | 65536
43 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # FilterGuiDemo
2 | This plugin is an example of a simple filter frequency response display.
3 | The filter response GUI component is drawn using JUCE path's and is an evaluation of the filters transfer function.
4 |
5 | The code is basic and could do with some improvements. At present the filter in this plugin is a simple one pole
6 | virtual analogue filter so as to make the code dealing with the drawing of the filter response path as simple as
7 | possible to understand.
8 |
9 | Feel free to make any suggestions to this repo/code, I am hoping this plugin will be useful for JUCE newbies and give a
10 | starting point for a handy GUI class for others. I will gradually attempt to make the filter response GUI component/class more
11 | reusable and generic for inclusion into people's projects.
12 |
13 | For example the FilterReponseDisplay class could be setup to use a callback / std::function object to calculate the filters magnitude response rather than depending on an AudioFilter object. The function object would simply need to be passed into the FilterResponseDisplay class constructor. This could make the class a little more generic, I’ll leave it up to the reader for now and will add this in on a future version.
14 |
15 | Future revisions of this example plugin will implement further filter types (Moog Ladder, SVF etc.) and response shapes along with oversampling and some other goodies.
16 |
17 |
18 |
19 |
20 | Thanks and credit to the following for allowing me to use some of their code/Ideas to build off.
21 |
22 | The guys at Semantic Audio for letting me use/pull apart their own filter display class - http://www.semanticaudio.co.uk
23 |
24 | Vadim Zavalishin for the excellent VA Filter paper - https://www.native-instruments.com/fileadmin/ni_media/downloads/pdf/VAFilterDesign_1.1.1.pdf
25 |
26 | Cheers
27 |
28 | Josh
--------------------------------------------------------------------------------
/JuceLibraryCode/JuceHeader.h:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | IMPORTANT! This file is auto-generated each time you save your
4 | project - if you alter its contents, your changes may be overwritten!
5 |
6 | This is the header file that your files should include in order to get all the
7 | JUCE library headers. You should avoid including the JUCE headers directly in
8 | your own source files, because that wouldn't pick up the correct configuration
9 | options for your app.
10 |
11 | */
12 |
13 | #ifndef __APPHEADERFILE_AOG7SJ__
14 | #define __APPHEADERFILE_AOG7SJ__
15 |
16 | #include "AppConfig.h"
17 | #include "modules/juce_audio_basics/juce_audio_basics.h"
18 | #include "modules/juce_audio_devices/juce_audio_devices.h"
19 | #include "modules/juce_audio_formats/juce_audio_formats.h"
20 | #include "modules/juce_audio_plugin_client/juce_audio_plugin_client.h"
21 | #include "modules/juce_audio_processors/juce_audio_processors.h"
22 | #include "modules/juce_core/juce_core.h"
23 | #include "modules/juce_cryptography/juce_cryptography.h"
24 | #include "modules/juce_data_structures/juce_data_structures.h"
25 | #include "modules/juce_events/juce_events.h"
26 | #include "modules/juce_graphics/juce_graphics.h"
27 | #include "modules/juce_gui_basics/juce_gui_basics.h"
28 | #include "modules/juce_gui_extra/juce_gui_extra.h"
29 | #include "modules/juce_opengl/juce_opengl.h"
30 | #include "modules/juce_video/juce_video.h"
31 |
32 | #if ! DONT_SET_USING_JUCE_NAMESPACE
33 | // If your code uses a lot of JUCE classes, then this will obviously save you
34 | // a lot of typing, but can be disabled by setting DONT_SET_USING_JUCE_NAMESPACE.
35 | using namespace juce;
36 | #endif
37 |
38 | #if ! JUCE_DONT_DECLARE_PROJECTINFO
39 | namespace ProjectInfo
40 | {
41 | const char* const projectName = "FilterGuiDemo";
42 | const char* const versionString = "1.0.0";
43 | const int versionNumber = 0x10000;
44 | }
45 | #endif
46 |
47 | #endif // __APPHEADERFILE_AOG7SJ__
48 |
--------------------------------------------------------------------------------
/Source/AudioDSPComponents/VAOnePoleFilter.h:
--------------------------------------------------------------------------------
1 | /*
2 | ==============================================================================
3 |
4 | VAOnePoleFilter.h
5 | Created: 9 Jul 2015 8:20:19pm
6 | Author: Joshua Marler
7 |
8 | ==============================================================================
9 | */
10 |
11 | #ifndef VAONEPOLEFILTER_H_INCLUDED
12 | #define VAONEPOLEFILTER_H_INCLUDED
13 |
14 | #include "JuceHeader.h"
15 | #include "AudioFilter.h"
16 |
17 |
18 | /*
19 | A very basic Virtual Analogue One Pole Filter based on calculations from The Art of VA Filter Design
20 | by Vadim Zavalishin see:
21 |
22 | NOTE : Need to implement oversampling as frequency response is incorrect at high frequencies approaching nyquist
23 | there is lost energy/gain which will be apparent on the filters response display (common issue with VA filters). You
24 | will notice the frequency response suddenly drops off as the cutoff approaches nyquist.
25 | This will be addressed in the next version.
26 |
27 | */
28 |
29 | class VAOnePoleFilter : public AudioFilter
30 | {
31 |
32 | public:
33 | VAOnePoleFilter();
34 |
35 | virtual ~VAOnePoleFilter();
36 |
37 | // Must be called before playback starts to set sample rate etc.
38 | void initializeFilter(float initSampRate, float initMinFrequency, float initMaxFrequency) override;
39 |
40 | void setCutoff(float cutoff) override;
41 |
42 | //Overriding base class filter response functions for VA One Pole response
43 | float getMagnitudeResponse(float freq) const override;
44 | float processFilter(float input, int channel) override;
45 |
46 | private:
47 | // z1 delay element/state holder (performing analgue intergration equivalent)
48 | // set as a stereo option for now, possibly a better way of setting up / handling
49 | // stereo input between filter and plugin processor code but this is nice and simple.
50 | float z1 [2];
51 |
52 | // Big G value for billinear cutoff/pre-warping
53 | float G = 0.0;
54 | };
55 |
56 | #endif // VAONEPOLEFILTER_H_INCLUDED
--------------------------------------------------------------------------------
/Source/PluginEditor.h:
--------------------------------------------------------------------------------
1 | /*
2 | ==============================================================================
3 |
4 | This file was auto-generated by the Introjucer!
5 |
6 | It contains the basic framework code for a JUCE plugin editor.
7 |
8 | ==============================================================================
9 | */
10 |
11 | #ifndef PLUGINEDITOR_H_INCLUDED
12 | #define PLUGINEDITOR_H_INCLUDED
13 |
14 | #include "../JuceLibraryCode/JuceHeader.h"
15 | #include "PluginProcessor.h"
16 | #include "GUIComponents/CustomLookAndFeel.h"
17 | #include "GUIComponents/FilterResponseDisplay.h"
18 | #include "GUIComponents/CustomSlider.h"
19 |
20 |
21 | //==============================================================================
22 | /**
23 | */
24 | class FilterGuiDemoAudioProcessorEditor : public AudioProcessorEditor,
25 | public ComboBoxListener
26 | {
27 | public:
28 |
29 | FilterGuiDemoAudioProcessorEditor (FilterGuiDemoAudioProcessor&);
30 | ~FilterGuiDemoAudioProcessorEditor();
31 | //==============================================================================
32 | void paint (Graphics&) override;
33 | void resized() override;
34 |
35 | //==============================================================================
36 | AudioProcessorParameter* getParameterFromSlider(const Slider* slider) const;
37 |
38 | //==============================================================================
39 | void comboBoxChanged (ComboBox* comboBoxThatHasChanged) override;
40 |
41 | private:
42 | // This reference is provided as a quick way for your editor to
43 | // access the processor object that created it.
44 | FilterGuiDemoAudioProcessor& processor;
45 |
46 | //GUI Components
47 | CustomLookAndFeel customLookAndFeel;
48 | FilterResponseDisplay filterResponseDisplay;
49 | std::unique_ptr frequencyCutoffSlider, filterGainSlider;
50 | ComboBox filterTypeDropDown;
51 | Label filterCutoffLabel, filterGainLabel;
52 |
53 | JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FilterGuiDemoAudioProcessorEditor)
54 | };
55 |
56 |
57 | #endif // PLUGINEDITOR_H_INCLUDED
58 |
--------------------------------------------------------------------------------
/Source/GUIComponents/FilterResponseDisplay.h:
--------------------------------------------------------------------------------
1 | /*
2 | ==============================================================================
3 |
4 | FilterResponseDisplay.h
5 | Created: 20 Jul 2015 3:22:56pm
6 | Author: Joshua Marler
7 |
8 | ==============================================================================
9 | */
10 |
11 | #ifndef FILTERRESPONSEDISPLAY_H_INCLUDED
12 | #define FILTERRESPONSEDISPLAY_H_INCLUDED
13 |
14 | #include "JuceHeader.h"
15 | #include "../AudioDSPComponents/AudioFilter.h"
16 |
17 | // A filter magnitude response display class
18 | // modified from and based on some code by semanticaudio
19 | // see https://github.com/semanticaudio/SAFE
20 | // Check the SAFE FilterGraph class for reference.
21 |
22 | class FilterResponseDisplay : public Component,
23 | public SliderListener
24 | {
25 | public:
26 | FilterResponseDisplay(const AudioFilter& filter);
27 | ~FilterResponseDisplay();
28 |
29 | //Function to update the filter being used for the response display incase of change in processor
30 | void setFilterToUse(const AudioFilter& filter);
31 |
32 | void paint(Graphics& g) override;
33 |
34 | //Filter response type drawing functions
35 | void drawLowpass();
36 | void drawHighpass();
37 |
38 | /*
39 | Setup as a slider listener so that filter display can be updated/call it's paint method when the relevant
40 | filter cutoff slider is moved.
41 |
42 | There are various possible ways to handle updating the display when a change in the filter occurs but this
43 | seems the simplest.
44 | */
45 | void sliderValueChanged (Slider* slider) override;
46 |
47 | //Sets the colour of the filters response curve
48 | void setMagResponseColour(Colour newColour);
49 |
50 | void setDisplayBackgroundColour(Colour newColour);
51 |
52 | float xAxisToFrequency (float xPos);
53 | float dbToYAxis(float db);
54 |
55 | void setMaxDecibels(float maxDB);
56 |
57 | private:
58 | //The AudioFilterResponse object the display will use to draw the magnitude response curve
59 | const AudioFilter* filterToUse;
60 |
61 | //Drawing / Graphics members
62 | Path magnitudeResponsePath;
63 | float filterPathThickness = 4.0;
64 | Colour magResponseColour;
65 | Colour displayBackgroundColor;
66 |
67 | float minFrequency = 0.0;
68 | float maxFrequency = 0.0;
69 | float maxDecibels = 0.0;
70 |
71 | };
72 |
73 | #endif // FILTERRESPONSEDISPLAY_H_INCLUDED
74 |
--------------------------------------------------------------------------------
/Source/Parameters/CustomAudioParameter.h:
--------------------------------------------------------------------------------
1 | /*
2 | ==============================================================================
3 |
4 | CustomAudioParameter.h
5 | Created: 19 Jun 2015 7:27:04pm
6 | Author: Joshua Marler
7 |
8 | ==============================================================================
9 | */
10 |
11 | #ifndef CustomAudioParameter_H_INCLUDED
12 | #define CustomAudioParameter_H_INCLUDED
13 |
14 | #include "../JuceLibraryCode/JuceHeader.h"
15 |
16 | /*
17 | Modified parameter class with some basic added extra's like ability to specify a callback funtion using std::function to be
18 | called whenever parameter value changes. This class uses a NormalisableRange range object which defaults to 0.0 - 1.0 range unless
19 | otherwise specified using the setNormalisableRange function.
20 |
21 | The value passed into setValue should still be between 0.0 and 1.0 - the NormalisableRange object is NOT used to convert values outside
22 | of a 0.0 - 1.0 range passed to setValue. The NormalisableRange converts 0.0 - 1.0 values to a custom range specified by the user which
23 | can then be used for display purposes and also passed to the setValueCallback function.
24 | */
25 | class CustomAudioParameter : public AudioProcessorParameterWithID
26 | {
27 | public:
28 |
29 | CustomAudioParameter(String initParameterID, String initParameterName, bool initUseNormalizedForCallback);
30 |
31 | //initSetValueCallback is a callback function you can specify (using a lambda etc) that will be called every time the parameter value changes.
32 | CustomAudioParameter(String initParameterID, String initParameterName, bool initUseNormalizedForCallback, std::function initSetValueCallback);
33 |
34 | ~CustomAudioParameter();
35 |
36 | float getValue() const override;
37 | void setValue(float newValue) override;
38 |
39 | void setNormalisableRange(NormalisableRange newRange);
40 | void setNormalisableRange(float start, float end);
41 |
42 | float getDefaultValue() const override;
43 | String getName(int maximumStringLength) const override;
44 |
45 | void setLabel(String newLabelText);
46 | String getLabel() const override;
47 |
48 | float getValueForText (const String& text) const override;
49 | String getText(float value, int = 0 /*Maximum String Length - default value provided/optional*/) const override;
50 |
51 | private:
52 |
53 | float defaultValue = 0.5;
54 | NormalisableRange range;
55 |
56 | //Using std::atomic for the host/GUI changeable value to stop any data race conditions etc. As per Timur's talk.
57 | //The gui thread will be updating this value via the ParameterSlider objects etc.
58 | std::atomic normalisedValue;
59 | std::atomic unnormalisedValue;
60 |
61 | bool useNormalizedForCallback;
62 |
63 | String name;
64 | String labelText = "";
65 |
66 | std::function setValueCallback = nullptr;
67 | };
68 |
69 |
70 |
71 |
72 | #endif // CustomAudioParameter_H_INCLUDED
73 |
--------------------------------------------------------------------------------
/Source/Parameters/CustomAudioParameter.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | ==============================================================================
3 |
4 | CustomAudioParameter.cpp
5 | Created: 19 Jun 2015 7:27:04pm
6 | Author: Joshua Marler
7 |
8 | ==============================================================================
9 | */
10 |
11 | #include "CustomAudioParameter.h"
12 |
13 | CustomAudioParameter::CustomAudioParameter(String initParameterID, String initParameterName, bool initUseNormalizedForCallback) : AudioProcessorParameterWithID(initParameterID, initParameterName), normalisedValue(0.0), unnormalisedValue(0.0)
14 | {
15 | name = initParameterName;
16 | useNormalizedForCallback = initUseNormalizedForCallback;
17 | range.start = 0.0;
18 | range.end = 1.0;
19 | }
20 |
21 |
22 | CustomAudioParameter::CustomAudioParameter(String initParameterID, String initParameterName, bool initUseNormalizedForCallback, std::function initSetValueCallback) : AudioProcessorParameterWithID(initParameterID, initParameterName), normalisedValue(0.0), unnormalisedValue(0.0)
23 | {
24 | name = initParameterName;
25 | useNormalizedForCallback = initUseNormalizedForCallback;
26 | setValueCallback = initSetValueCallback;
27 | range.start = 0.0;
28 | range.end = 1.0;
29 | }
30 |
31 |
32 | CustomAudioParameter::~CustomAudioParameter()
33 | {
34 |
35 | }
36 |
37 |
38 | float CustomAudioParameter::getValue() const
39 | {
40 | return normalisedValue.load();
41 | }
42 |
43 |
44 | void CustomAudioParameter::setValue (float newValue)
45 | {
46 | normalisedValue.store(newValue);
47 | unnormalisedValue.store(range.convertFrom0to1(newValue));
48 |
49 | if (setValueCallback != nullptr)
50 | {
51 | if (useNormalizedForCallback)
52 | {
53 | setValueCallback(normalisedValue.load());
54 | }
55 | else
56 | {
57 | setValueCallback(unnormalisedValue.load());
58 | }
59 | }
60 | }
61 |
62 | void CustomAudioParameter::setNormalisableRange(NormalisableRange newRange)
63 | {
64 | range = newRange;
65 | }
66 |
67 | void CustomAudioParameter::setNormalisableRange(float start, float end)
68 | {
69 | range.start = start;
70 | range.end = end;
71 | }
72 |
73 | float CustomAudioParameter::getDefaultValue() const
74 | {
75 | return defaultValue;
76 | }
77 |
78 |
79 | String CustomAudioParameter::getName(int maximumStringLength) const
80 | {
81 | return name;
82 | }
83 |
84 | void CustomAudioParameter::setLabel(String newLabelText)
85 | {
86 | labelText = newLabelText;
87 | }
88 |
89 | String CustomAudioParameter::getLabel() const
90 | {
91 | return labelText;
92 | }
93 |
94 |
95 | float CustomAudioParameter::getValueForText(const String& text) const
96 | {
97 | return range.convertFrom0to1(text.getFloatValue());
98 | }
99 |
100 |
101 | String CustomAudioParameter::getText(float value, int/*Maximum String Length - default value provided/optional*/) const
102 | {
103 | String text = String(range.convertFrom0to1(value)) + getLabel();
104 | return text;
105 | }
106 |
107 |
108 |
--------------------------------------------------------------------------------
/Source/AudioDSPComponents/AudioFilter.h:
--------------------------------------------------------------------------------
1 | /*
2 | ==============================================================================
3 |
4 | AudioFilter.h
5 | Created: 25 Jul 2015 10:05:58am
6 | Author: Joshua Marler
7 |
8 | ==============================================================================
9 | */
10 |
11 | #ifndef AUDIOFILTER_H_INCLUDED
12 | #define AUDIOFILTER_H_INCLUDED
13 |
14 | #include "JuceHeader.h"
15 |
16 | //Abstract audio filter base class
17 | class AudioFilter
18 | {
19 | public:
20 |
21 | AudioFilter();
22 |
23 | virtual ~AudioFilter();
24 |
25 | //Filters deriving from this class must implement their process method
26 | virtual float processFilter (float input, int channel) = 0;
27 |
28 | /*
29 | Filters deriving from this class must implement their own initialization code - i.e for flushing storage registers/state holders etc.
30 | Must be called before playback starts to set sample rate etc.
31 | */
32 | virtual void initializeFilter (float initSampleRate, float initMinFrequency, float initMaxFrequency) = 0;
33 |
34 | inline void setSampleRate (float newSampRate) {sampleRate = newSampRate;}
35 | inline float getSampleRate() const {return sampleRate;}
36 |
37 | inline void setMinFrequency (float newMinFrequency) {minFrequency = newMinFrequency;}
38 | inline float getMinFrequency() const {return minFrequency;}
39 |
40 | inline void setMaxFrequency (float newMaxFrequency) {maxFrequency = newMaxFrequency;}
41 | inline float getMaxFrequency() const {return maxFrequency;}
42 |
43 |
44 | /*
45 | Parameter set and get methods made virtual to facilitate use in different types of filters - i.e virtual analogue filters where
46 | cutoff frequencies may need to be pre-warped etc.
47 | */
48 | virtual void setCutoff (float newCutoff);
49 | virtual float getCutoff() const;
50 | virtual void setQFactor (float newQFactor);
51 | virtual float getQFactor() const;
52 | virtual void setGain (float newGain);
53 | virtual float getGain() const;
54 |
55 | /*
56 | Filter response functions that can be overriden in baseclass to return the filters magnitude and phase response.
57 | These can be used to provide frequency response for displays and GUI components etc. Default implementations just return 0.0.
58 | These functions do not HAVE to be implemented - the filter object will run fine without them.
59 | */
60 | virtual float getMagnitudeResponse(float freq) const;
61 | virtual float getPhaseResponse(float freq) const;
62 |
63 | void setFilterType (int newFilterType);
64 | int getFilterType() const;
65 |
66 | //Filter types / response shapes - lowpass, highpass etc.
67 | enum filterTypeList
68 | {
69 | LowPass = 0,
70 | HighPass
71 | };
72 |
73 | protected:
74 |
75 | float sampleRate = 0.0;
76 | float minFrequency = 0.0;
77 | float maxFrequency = 0.0;
78 |
79 | //Wrap these as std::atomic ? What if they are updated by lfo etc and the gui thread also reads them in some way through magnitudeResponse call etc.
80 | float cutoffFrequency = 0.0;
81 | float filterGain = 1.0;
82 | float qFactor = 0.0;
83 |
84 | int filterType = 0;
85 | };
86 |
87 | #endif // AUDIOFILTER_H_INCLUDED
88 |
--------------------------------------------------------------------------------
/Source/PluginProcessor.h:
--------------------------------------------------------------------------------
1 | /*
2 | ==============================================================================
3 |
4 | This file was auto-generated by the Introjucer!
5 |
6 | It contains the basic framework code for a JUCE plugin processor.
7 |
8 | ==============================================================================
9 | */
10 |
11 | #ifndef PLUGINPROCESSOR_H_INCLUDED
12 | #define PLUGINPROCESSOR_H_INCLUDED
13 |
14 | #include "../JuceLibraryCode/JuceHeader.h"
15 | #include "AudioDSPComponents/VAOnePoleFilter.h"
16 | #include "Parameters/CustomAudioParameter.h"
17 |
18 |
19 | //==============================================================================
20 | /**
21 | */
22 | class FilterGuiDemoAudioProcessor : public AudioProcessor
23 | {
24 | public:
25 | //==============================================================================
26 | FilterGuiDemoAudioProcessor();
27 | ~FilterGuiDemoAudioProcessor();
28 |
29 | //==============================================================================
30 | void prepareToPlay (double sampleRate, int samplesPerBlock) override;
31 | void releaseResources() override;
32 |
33 | void processBlock (AudioSampleBuffer&, MidiBuffer&) override;
34 |
35 | //==============================================================================
36 | AudioProcessorEditor* createEditor() override;
37 | bool hasEditor() const override;
38 |
39 | //==============================================================================
40 | const String getName() const override;
41 |
42 | bool acceptsMidi() const override;
43 | bool producesMidi() const override;
44 | bool silenceInProducesSilenceOut() const override;
45 | double getTailLengthSeconds() const override;
46 |
47 | //==============================================================================
48 | int getNumPrograms() override;
49 | int getCurrentProgram() override;
50 | void setCurrentProgram (int index) override;
51 | const String getProgramName (int index) override;
52 | void changeProgramName (int index, const String& newName) override;
53 |
54 | //==============================================================================
55 | void getStateInformation (MemoryBlock& destData) override;
56 | void setStateInformation (const void* data, int sizeInBytes) override;
57 |
58 | //Returns the processors AudioFilter instance for GUI code etc.
59 | AudioFilter& getAudioFilter();
60 |
61 | CustomAudioParameter* filterCutoffParam;
62 | CustomAudioParameter* filterGainParam;
63 |
64 | // these are used to persist the UI's size - the values are stored along with the
65 | // filter's other parameters, and the UI component will update them when it gets
66 | // resized.
67 | int lastUIWidth, lastUIHeight;
68 |
69 | private:
70 | //==============================================================================
71 |
72 |
73 | std::unique_ptr filter1;
74 |
75 | //CustomAudioParameter* filterCutoffParam;
76 | //CustomAudioParameter* filterGainParam;
77 |
78 | //Default setup values for filter etc.
79 | const float defaultSampleRate = 44100.00;
80 | const float defaultMinFilterFrequency = 20.00;
81 | const float defaultMaxFilterFrequency = 20000.00;
82 |
83 | //==============================================================================
84 | JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FilterGuiDemoAudioProcessor)
85 | };
86 |
87 |
88 | #endif // PLUGINPROCESSOR_H_INCLUDED
89 |
--------------------------------------------------------------------------------
/Source/AudioDSPComponents/VAOnePoleFilter.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | ==============================================================================
3 |
4 | VAOnePoleFilter.cpp
5 | Created: 9 Jul 2015 8:20:19pm
6 | Author: Joshua Marler
7 |
8 | ==============================================================================
9 | */
10 |
11 | #include "VAOnePoleFilter.h"
12 |
13 | VAOnePoleFilter::VAOnePoleFilter()
14 | {
15 |
16 | }
17 |
18 | VAOnePoleFilter::~VAOnePoleFilter()
19 | {
20 |
21 | }
22 |
23 | //Set variables and flush state registers in initialization function. Must be called before playback starts
24 | void VAOnePoleFilter::initializeFilter(float initSampleRate, float initMinFrequency, float initMaxFrequency)
25 | {
26 | this->sampleRate = initSampleRate;
27 | this->minFrequency = initMinFrequency;
28 | this->maxFrequency = initMaxFrequency;
29 |
30 | //clear the delay elements/state holders
31 | z1[0] = 0.0;
32 | z1[1] = 0.0;
33 | }
34 |
35 |
36 | void VAOnePoleFilter::setCutoff(float newCutoff)
37 | {
38 | this->cutoffFrequency = newCutoff;
39 |
40 | //Cutoff prewarping, billinear transform filters - see Art Of VA Filter Design.
41 | float wd = 2 * M_PI * this->cutoffFrequency;
42 | float T = 1/this->sampleRate;
43 |
44 | /* Desired analogue frequency / these are virtual analogue filters so this is the cutoff / frequency response we require for out filter algorithm */
45 | float wa = (2/T) * tan(wd*T/2);
46 | float g = wa * T/2;
47 | G = g/(1.0 + g);
48 | }
49 |
50 |
51 | float VAOnePoleFilter::processFilter(float input, int channel)
52 | {
53 | float output = 0.0;
54 | float v = (input - z1[channel]) * G;
55 | float lowpassOutput = v + z1[channel];
56 |
57 | //Update the z1 delay / state holder with new filter output for use in next sample
58 | z1 [channel]= lowpassOutput + v;
59 |
60 | float highpassOutput = input - lowpassOutput;
61 |
62 | switch (this->filterType) {
63 | case AudioFilter::filterTypeList::LowPass:
64 | output = this->filterGain * lowpassOutput;
65 | break;
66 | case AudioFilter::filterTypeList::HighPass:
67 | output = this->filterGain * highpassOutput;
68 | break;
69 | default:
70 | break;
71 | }
72 |
73 | return output;
74 | }
75 |
76 | float VAOnePoleFilter::getMagnitudeResponse(float frequency) const
77 | {
78 | float magnitude = 0.0;
79 | float T = 1/this->sampleRate;
80 |
81 | float wdCutoff = 2 * M_PI * this->cutoffFrequency;
82 |
83 | //Calculating pre-warped/analogue cutoff frequency to use in virtual analogue frequeny response calculations
84 | float cutOff = (2/T) * tan(wdCutoff*T/2);
85 |
86 | //Digital frequency to evaluate
87 | float wdEval = 2 * M_PI * frequency;
88 | float sValue = (2/T) * tan(wdEval*T/2);
89 |
90 |
91 | /* This is the digital transfer function which is equal to the analogue transfer function
92 | evaluated at H(s) where s = (2/T) * tan(wd*T/2) hence why the cutoff used is the pre warped analogue equivalent.
93 | See Art Of VA Filter Design 3.8 Bilinear Transform Section */
94 | switch (this->filterType) {
95 | case AudioFilter::filterTypeList::LowPass:
96 | //VA Lowpass Frequency response wc/s+wc
97 | magnitude = cutOff/(sValue + cutOff);
98 | break;
99 | case AudioFilter::filterTypeList::HighPass:
100 | //VA Highpass Frequency response s/s+wc
101 | magnitude = sValue/(sValue + cutOff);
102 | break;
103 | default:
104 | break;
105 | }
106 |
107 | magnitude = magnitude * this->filterGain;
108 |
109 | //Convert to db for log db response display
110 | magnitude = Decibels::gainToDecibels(magnitude);
111 | return magnitude;
112 | }
113 |
114 |
115 |
116 |
117 |
118 |
119 |
--------------------------------------------------------------------------------
/Source/PluginEditor.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | ==============================================================================
3 |
4 | This file was auto-generated by the Introjucer!
5 |
6 | It contains the basic framework code for a JUCE plugin editor.
7 |
8 | ==============================================================================
9 | */
10 |
11 | #include "PluginProcessor.h"
12 | #include "PluginEditor.h"
13 |
14 |
15 | //==============================================================================
16 | FilterGuiDemoAudioProcessorEditor::FilterGuiDemoAudioProcessorEditor (FilterGuiDemoAudioProcessor& p)
17 | : AudioProcessorEditor (&p), processor (p), customLookAndFeel(),
18 | filterResponseDisplay(processor.getAudioFilter()), frequencyCutoffSlider(new CustomSlider (*processor.filterCutoffParam)),filterGainSlider(new CustomSlider (*processor.filterGainParam))
19 | {
20 | // Make sure that before the constructor has finished, you've set the
21 | // editor's size to whatever you need it to be.
22 | setSize (600, 500);
23 |
24 | FilterGuiDemoAudioProcessorEditor::setLookAndFeel(&customLookAndFeel);
25 |
26 | //Setup Components
27 | addAndMakeVisible(*frequencyCutoffSlider);
28 | frequencyCutoffSlider->setName("FilterCutoff");
29 | frequencyCutoffSlider->setSliderStyle(Slider::Rotary);
30 | frequencyCutoffSlider->setRange(0.0, 1.0);
31 |
32 | //Logarithmic frequency - 0.5 skew factor effectivley makes this a volt-octave knob.
33 | frequencyCutoffSlider->setSkewFactor(0.5);
34 | frequencyCutoffSlider->setColour(Slider::rotarySliderOutlineColourId, Colours::greenyellow);
35 | frequencyCutoffSlider->setColour(Slider::rotarySliderFillColourId, Colours::greenyellow);
36 |
37 | addAndMakeVisible(*filterGainSlider);
38 | filterGainSlider->setName("FilterGain");
39 | filterGainSlider->setSliderStyle(Slider::Rotary);
40 | filterGainSlider->setRange(0.0, 1.0, 0.05);
41 | filterGainSlider->setColour(Slider::rotarySliderOutlineColourId, Colours::greenyellow);
42 | filterGainSlider->setColour(Slider::rotarySliderFillColourId, Colours::greenyellow);
43 |
44 | addAndMakeVisible(filterCutoffLabel);
45 | filterCutoffLabel.setText("Cutoff", juce::NotificationType::dontSendNotification);
46 | filterCutoffLabel.setFont(Font ("Cracked", 27.50f, Font::plain));
47 | filterCutoffLabel.setColour(Label::textColourId, Colours::greenyellow);
48 |
49 | addAndMakeVisible(filterGainLabel);
50 | filterGainLabel.setText("Gain", juce::NotificationType::dontSendNotification);
51 | filterGainLabel.setFont(Font ("Cracked", 27.50f, Font::plain));
52 | filterGainLabel.setColour(Label::textColourId, Colours::greenyellow);
53 |
54 | addAndMakeVisible(filterTypeDropDown);
55 | filterTypeDropDown.addItem("LowPass", 1);
56 | filterTypeDropDown.addItem("HighPass", 2);
57 | filterTypeDropDown.setColour(ComboBox::outlineColourId, Colours::greenyellow);
58 | filterTypeDropDown.setColour(ComboBox::backgroundColourId, Colours::black);
59 | filterTypeDropDown.setColour(ComboBox::textColourId, Colours::greenyellow);
60 | filterTypeDropDown.setColour(ComboBox::buttonColourId, Colours::greenyellow);
61 | filterTypeDropDown.setSelectedId(1);
62 | filterTypeDropDown.addListener(this);
63 |
64 | addAndMakeVisible(filterResponseDisplay);
65 | filterResponseDisplay.setMagResponseColour(Colours::greenyellow);
66 | filterResponseDisplay.setDisplayBackgroundColour(Colours::darkgrey);
67 | filterResponseDisplay.setBounds(50, 125, 500, 200);
68 |
69 | //Add the filter display as a listener to the cutoff and gain sliders for updates.
70 | frequencyCutoffSlider->addListener(&filterResponseDisplay);
71 | filterGainSlider->addListener(&filterResponseDisplay);
72 | }
73 |
74 | FilterGuiDemoAudioProcessorEditor::~FilterGuiDemoAudioProcessorEditor()
75 | {
76 | }
77 |
78 |
79 | //==============================================================================
80 | void FilterGuiDemoAudioProcessorEditor::comboBoxChanged(ComboBox* comboBoxThatChanged)
81 | {
82 | //In here set filter type and also update filter response display's filter type
83 | if (comboBoxThatChanged == &filterTypeDropDown)
84 | {
85 | int filterTypeIndex = filterTypeDropDown.getSelectedItemIndex();
86 | processor.getAudioFilter().setFilterType(filterTypeIndex);
87 |
88 | //Repaint response display for filter type change
89 | filterResponseDisplay.repaint();
90 | }
91 | }
92 |
93 | //==============================================================================
94 | void FilterGuiDemoAudioProcessorEditor::paint (Graphics& g)
95 | {
96 | g.fillAll (Colours::black);
97 | }
98 |
99 | void FilterGuiDemoAudioProcessorEditor::resized()
100 | {
101 | filterResponseDisplay.setBounds(50, 125, 500, 200);
102 | filterTypeDropDown.setBounds(225, 50, 150, 30);
103 |
104 | filterCutoffLabel.setBounds(85, 358, 130, 20);
105 | frequencyCutoffSlider->setBounds(50, 386, 135, 105);
106 | frequencyCutoffSlider->setTextBoxStyle(juce::Slider::TextEntryBoxPosition::TextBoxBelow, true, 75, 20);
107 |
108 | filterGainLabel.setBounds(443, 358, 130, 20);
109 | filterGainSlider->setBounds(400, 386, 135, 105);
110 | filterGainSlider->setTextBoxStyle(juce::Slider::TextEntryBoxPosition::TextBoxBelow, true, 75, 20);
111 | }
112 |
--------------------------------------------------------------------------------
/Source/GUIComponents/FilterResponseDisplay.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | ==============================================================================
3 |
4 | FilterResponseDisplay.cpp
5 | Created: 20 Jul 2015 3:22:56pm
6 | Author: Joshua Marler
7 |
8 | ==============================================================================
9 | */
10 |
11 | #include "FilterResponseDisplay.h"
12 |
13 |
14 | FilterResponseDisplay::FilterResponseDisplay(const AudioFilter& filter)
15 | {
16 | filterToUse = &filter;
17 | minFrequency = filterToUse->getMinFrequency();
18 | maxFrequency = filterToUse->getMaxFrequency();
19 |
20 | /*
21 | Sets the filter response displays min - max decibel range - Try changing this value to lower or higher decibel ranges
22 | to see the effect on the frequency response that is shown. If implementing a filter with resonant peaks you will need
23 | to ensure the peak values do not exceed the maxDecibels level.
24 | */
25 | maxDecibels = 20.00;
26 | }
27 |
28 |
29 | FilterResponseDisplay::~FilterResponseDisplay()
30 | {
31 |
32 | }
33 |
34 | void FilterResponseDisplay::setFilterToUse(const AudioFilter& filter)
35 | {
36 | filterToUse = &filter;
37 | minFrequency = filterToUse->getMinFrequency();
38 | maxFrequency = filterToUse->getMaxFrequency();
39 | }
40 |
41 | void FilterResponseDisplay::paint(Graphics& g)
42 | {
43 | float width = (float) getWidth();
44 | float height = (float) getHeight();
45 |
46 | g.setColour(displayBackgroundColor);
47 | g.fillRect(0.0, 0.0, width, height);
48 |
49 | magnitudeResponsePath.clear();
50 |
51 | int filterType = filterToUse->getFilterType();
52 | switch (filterType) {
53 | case AudioFilter::filterTypeList::LowPass:
54 | drawLowpass();
55 | break;
56 | case AudioFilter::filterTypeList::HighPass:
57 | drawHighpass();
58 | break;
59 | }
60 |
61 | //Close the response path drawn
62 | magnitudeResponsePath.closeSubPath();
63 |
64 | g.setColour(magResponseColour);
65 | g.strokePath(magnitudeResponsePath, PathStrokeType(filterPathThickness));
66 |
67 | /*
68 | Fill area under/inside path with same colour at a lower alpha / highlight value.
69 | Try setting magResponseColour.withAlpha value to different values to get a fill shade you like.
70 | */
71 | g.setColour(magResponseColour.withAlpha((uint8) 0x9a));
72 | g.fillPath(magnitudeResponsePath);
73 |
74 | }
75 |
76 | //Draws filter display path for Lowpas response
77 | void FilterResponseDisplay::drawLowpass()
78 | {
79 | float freq = 0.0;
80 | float magnitudeDBValue = 0.0;
81 |
82 | /*
83 | LowPass so start path on left hand side of component i.e at 0.0f - using 0.0f - (filterPathThickness/2) for asthetic purposes
84 | Try commeting out - (filterPathThickness/2) to see the effect. This line hides the highlighted path edge so that the path edge
85 | highlight shows only on the top of the magnitude response path.
86 | */
87 | magnitudeResponsePath.startNewSubPath((0.0f - (filterPathThickness/2)), (getBottom() - (filterPathThickness/2)));
88 | magnitudeDBValue = filterToUse->getMagnitudeResponse(minFrequency);
89 | magnitudeResponsePath.lineTo((0.0f - (filterPathThickness/2)) , dbToYAxis(magnitudeDBValue));
90 |
91 | for (float xPos = 0.0; xPos < ((float) getWidth() + (filterPathThickness/2)); xPos += (filterPathThickness/2))
92 | {
93 | //Get the frequency value for the filter's magnitude response calculation
94 | freq = xAxisToFrequency(xPos);
95 | magnitudeDBValue = filterToUse->getMagnitudeResponse(freq);
96 | magnitudeResponsePath.lineTo(xPos, dbToYAxis(magnitudeDBValue));
97 | }
98 |
99 | magnitudeDBValue = filterToUse->getMagnitudeResponse(maxFrequency);
100 | magnitudeResponsePath.lineTo(((float) getWidth() + (filterPathThickness/2)), dbToYAxis(magnitudeDBValue));
101 |
102 | /*
103 | Dirty Trick to close the path nicely when cutoff is at max level (this is not apparent for virtual analogue filters that have not been
104 | oversampled when cutoff is close to nyquist as the response is pulled to zero). Try commenting this line out and running the plugin at
105 | higher sample rate i.e 96khz to see the visual result of the path closing without this.
106 | */
107 | magnitudeResponsePath.lineTo(((float) getWidth() + (filterPathThickness/2)), (getBottom() - (filterPathThickness/2)));
108 |
109 | }
110 |
111 | //Draws filter display path for Highpass response
112 | void FilterResponseDisplay::drawHighpass()
113 | {
114 | float freq = 0.0;
115 | float magnitudeDBValue = 0.0;
116 |
117 | //If HighPass start path on right hand side of component i.e at component width.
118 | magnitudeDBValue = filterToUse->getMagnitudeResponse(maxFrequency);
119 | magnitudeResponsePath.startNewSubPath(((float) getWidth() + (filterPathThickness/2)), (getBottom() - (filterPathThickness/2)));
120 | magnitudeResponsePath.lineTo(((float) getWidth() + (filterPathThickness/2)), dbToYAxis(magnitudeDBValue));
121 |
122 | for (float xPos = ((float) getWidth()); xPos > (filterPathThickness/2); xPos -= (filterPathThickness/2))
123 | {
124 | //Get the frequency value for the filter's magnitude response calculation
125 | freq = xAxisToFrequency(xPos);
126 | magnitudeDBValue = filterToUse->getMagnitudeResponse(freq);
127 | magnitudeResponsePath.lineTo(xPos, dbToYAxis(magnitudeDBValue));
128 | }
129 |
130 | magnitudeDBValue = filterToUse->getMagnitudeResponse(minFrequency);
131 | magnitudeResponsePath.lineTo ((0.0f - (filterPathThickness/2)), dbToYAxis(magnitudeDBValue));
132 |
133 | /*
134 | Dirty trick again to close the path nicely when cutoff at min level for High Pass - try cmmenting this line out to se the visual
135 | effect on the reponse path closing without it
136 | */
137 | magnitudeResponsePath.lineTo ((0.0f - (filterPathThickness/2)), (getBottom() - (filterPathThickness/2)));
138 | }
139 |
140 |
141 | void FilterResponseDisplay::setMagResponseColour(Colour newColour)
142 | {
143 | magResponseColour = newColour;
144 | }
145 |
146 |
147 | void FilterResponseDisplay::setDisplayBackgroundColour(Colour newColour)
148 | {
149 | displayBackgroundColor = newColour;
150 | }
151 |
152 | //Converts position along the FilterReponseDisplay component's X-Axis into frequency for use in filter response calculation.
153 | float FilterResponseDisplay::xAxisToFrequency(float xPos)
154 | {
155 | float width = getWidth();
156 | //Computes frequency from position on x axis of component. So if the xPos is equal to the component width the value returned will be maxFrequency.
157 | float frequency = minFrequency * pow((maxFrequency / minFrequency), (xPos / width));
158 | return frequency;
159 | }
160 |
161 |
162 | float FilterResponseDisplay::dbToYAxis(float dbGain)
163 | {
164 | float height = getHeight();
165 |
166 | //Scale gain with this value, height of component is divded by maxDB * 2 for -max to +max db response display
167 | float scale = - (height) / (maxDecibels * 2);
168 | float scaledDbGain = dbGain * scale;
169 |
170 | /*
171 | Negative db values will result in a negative yposition so add height/2 to result to scale into
172 | correct component position for drawing. Test these calculations with a dbGain value equal to maxDecibels and
173 | yPostion computed will be equal to the filterResponseDisplay's height as is correct.
174 | */
175 | float yPosition = scaledDbGain + (height / 2);
176 | return yPosition;
177 | }
178 |
179 | void FilterResponseDisplay::setMaxDecibels(float maxDB)
180 | {
181 | maxDecibels = maxDB;
182 | }
183 |
184 | void FilterResponseDisplay::sliderValueChanged (Slider* slider)
185 | {
186 | this->repaint();
187 | }
188 |
--------------------------------------------------------------------------------
/Source/PluginProcessor.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | ==============================================================================
3 |
4 | This file was auto-generated by the Introjucer!
5 |
6 | It contains the basic framework code for a JUCE plugin processor.
7 |
8 | ==============================================================================
9 | */
10 |
11 | #include "PluginProcessor.h"
12 | #include "PluginEditor.h"
13 |
14 |
15 | //==============================================================================
16 | FilterGuiDemoAudioProcessor::FilterGuiDemoAudioProcessor() : filter1(new VAOnePoleFilter())
17 | {
18 | /* The lambda is capturing a value copy of the this pointer to the audio processor. The processor will be destroyed after the parameter object so
19 | this is safe.*/
20 | auto cutoffParamCallback = [this] (float newCutoff){this->filter1->setCutoff(newCutoff);};
21 | filterCutoffParam = new CustomAudioParameter("FilterCutoff", "FilterCutoff", false, cutoffParamCallback);
22 |
23 | //This param represents a filters cutoff frequency so appending Hz string to label for display purposes.
24 | filterCutoffParam->setLabel("Hz");
25 |
26 | /*
27 | The filters min and max frequency will be used as normalized range values and values in this range will be passed to the set value
28 | callback function.
29 | */
30 | filterCutoffParam->setNormalisableRange(defaultMinFilterFrequency, defaultMaxFilterFrequency);
31 |
32 | auto gainParamCallback = [this] (float gain) {this->filter1->setGain(gain);};
33 | filterGainParam = new CustomAudioParameter("FilterGain", "FilterGain", true, gainParamCallback);
34 |
35 | addParameter(filterCutoffParam);
36 | addParameter(filterGainParam);
37 | }
38 |
39 | FilterGuiDemoAudioProcessor::~FilterGuiDemoAudioProcessor()
40 | {
41 | }
42 |
43 | //==============================================================================
44 | const String FilterGuiDemoAudioProcessor::getName() const
45 | {
46 | return JucePlugin_Name;
47 | }
48 |
49 | bool FilterGuiDemoAudioProcessor::acceptsMidi() const
50 | {
51 | #if JucePlugin_WantsMidiInput
52 | return true;
53 | #else
54 | return false;
55 | #endif
56 | }
57 |
58 | bool FilterGuiDemoAudioProcessor::producesMidi() const
59 | {
60 | #if JucePlugin_ProducesMidiOutput
61 | return true;
62 | #else
63 | return false;
64 | #endif
65 | }
66 |
67 | bool FilterGuiDemoAudioProcessor::silenceInProducesSilenceOut() const
68 | {
69 | return false;
70 | }
71 |
72 | double FilterGuiDemoAudioProcessor::getTailLengthSeconds() const
73 | {
74 | return 0.0;
75 | }
76 |
77 | int FilterGuiDemoAudioProcessor::getNumPrograms()
78 | {
79 | return 1; // NB: some hosts don't cope very well if you tell them there are 0 programs,
80 | // so this should be at least 1, even if you're not really implementing programs.
81 | }
82 |
83 | int FilterGuiDemoAudioProcessor::getCurrentProgram()
84 | {
85 | return 0;
86 | }
87 |
88 | void FilterGuiDemoAudioProcessor::setCurrentProgram (int index)
89 | {
90 | }
91 |
92 | const String FilterGuiDemoAudioProcessor::getProgramName (int index)
93 | {
94 | return String();
95 | }
96 |
97 | void FilterGuiDemoAudioProcessor::changeProgramName (int index, const String& newName)
98 | {
99 | }
100 |
101 | //==============================================================================
102 | void FilterGuiDemoAudioProcessor::prepareToPlay (double sampleRate, int samplesPerBlock)
103 | {
104 | // Use this method as the place to do any pre-playback
105 | // initialisation that you need..
106 |
107 | //Initialize our audio filter for playback.
108 | filter1->initializeFilter(sampleRate, defaultMinFilterFrequency, defaultMaxFilterFrequency);
109 | }
110 |
111 | void FilterGuiDemoAudioProcessor::releaseResources()
112 | {
113 | // When playback stops, you can use this as an opportunity to free up any
114 | // spare memory, etc.
115 | }
116 |
117 | void FilterGuiDemoAudioProcessor::processBlock (AudioSampleBuffer& buffer, MidiBuffer& midiMessages)
118 | {
119 | float numSamples = buffer.getNumSamples();
120 | float currentSampleRate = getSampleRate();
121 |
122 | //Handles filter being added onto an already playing audio track where some hosts will not call prepare to play method.
123 | if (filter1->getSampleRate() != currentSampleRate)
124 | {
125 | filter1->initializeFilter(currentSampleRate, defaultMinFilterFrequency, defaultMaxFilterFrequency);
126 | }
127 |
128 | // In case we have more outputs than inputs, this code clears any output
129 | // channels that didn't contain input data, (because these aren't
130 | // guaranteed to be empty - they may contain garbage).
131 | // I've added this to avoid people getting screaming feedback
132 | // when they first compile the plugin, but obviously you don't need to
133 | // this code if your algorithm already fills all the output channels.
134 | for (int i = getTotalNumInputChannels(); i < getTotalNumOutputChannels(); ++i)
135 | buffer.clear (i, 0, buffer.getNumSamples());
136 |
137 | // MAIN AUDIO PROCESSING BLOCK. PROCESS FILTER TWICE FOR STEREO CHANNELS
138 | for (int channel = 0; channel < getTotalNumInputChannels(); ++channel)
139 | {
140 | const float* input = buffer.getReadPointer(channel);
141 | float* output = buffer.getWritePointer (channel);
142 |
143 | for (int i = 0; i < numSamples; i++)
144 | {
145 | output[i] = filter1->processFilter(input[i], channel);
146 | }
147 | }
148 | }
149 |
150 | //==============================================================================
151 | AudioFilter& FilterGuiDemoAudioProcessor::getAudioFilter()
152 | {
153 | return *filter1;
154 | }
155 |
156 | //==============================================================================
157 | bool FilterGuiDemoAudioProcessor::hasEditor() const
158 | {
159 | return true; // (change this to false if you choose to not supply an editor)
160 | }
161 |
162 | AudioProcessorEditor* FilterGuiDemoAudioProcessor::createEditor()
163 | {
164 | return new FilterGuiDemoAudioProcessorEditor (*this);
165 | }
166 |
167 | //==============================================================================
168 | void FilterGuiDemoAudioProcessor::getStateInformation (MemoryBlock& destData)
169 | {
170 | // You should use this method to store your parameters in the memory block.
171 | // You could do that either as raw data, or use the XML or ValueTree classes
172 | // as intermediaries to make it easy to save and load complex data.
173 |
174 | // Create an outer XML element..
175 | XmlElement xml ("MYPLUGINSETTINGS");
176 |
177 | // Store the values of all our parameters, using their param ID as the XML attribute
178 | for (int i = 0; i < getNumParameters(); ++i)
179 | if (AudioProcessorParameterWithID* p = dynamic_cast (getParameters().getUnchecked(i)))
180 | xml.setAttribute (p->paramID, p->getValue());
181 |
182 | // then use this helper function to stuff it into the binary blob and return it..
183 | copyXmlToBinary (xml, destData);
184 | }
185 |
186 | void FilterGuiDemoAudioProcessor::setStateInformation (const void* data, int sizeInBytes)
187 | {
188 | // You should use this method to restore your parameters from this memory block,
189 | // whose contents will have been created by the getStateInformation() call.
190 | // This getXmlFromBinary() helper function retrieves our XML from the binary blob..
191 | ScopedPointer xmlState (getXmlFromBinary (data, sizeInBytes));
192 |
193 | if (xmlState != nullptr)
194 | {
195 | // make sure that it's actually our type of XML object..
196 | if (xmlState->hasTagName ("MYPLUGINSETTINGS"))
197 | {
198 | // Now reload our parameters..
199 | for (int i = 0; i < getNumParameters(); ++i)
200 | if (AudioProcessorParameterWithID* p = dynamic_cast (getParameters().getUnchecked(i)))
201 | p->setValueNotifyingHost ((float) xmlState->getDoubleAttribute (p->paramID, p->getValue()));
202 | }
203 | }
204 | }
205 |
206 | //==============================================================================
207 | // This creates new instances of the plugin..
208 | AudioProcessor* JUCE_CALLTYPE createPluginFilter()
209 | {
210 | return new FilterGuiDemoAudioProcessor();
211 | }
212 |
--------------------------------------------------------------------------------
/FilterGuiDemo.jucer:
--------------------------------------------------------------------------------
1 |
2 |
3 |
14 |
15 |
16 |
17 |
19 |
21 |
22 |
23 |
25 |
27 |
29 |
31 |
33 |
34 |
35 |
36 |
37 |
38 |
40 |
42 |
43 |
45 |
47 |
49 |
50 |
51 |
52 |
53 |
55 |
56 |
58 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
--------------------------------------------------------------------------------
/JuceLibraryCode/AppConfig.h:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | IMPORTANT! This file is auto-generated each time you save your
4 | project - if you alter its contents, your changes may be overwritten!
5 |
6 | There's a section below where you can add your own custom code safely, and the
7 | Introjucer will preserve the contents of that block, but the best way to change
8 | any of these definitions is by using the Introjucer's project settings.
9 |
10 | Any commented-out settings will assume their default values.
11 |
12 | */
13 |
14 | #ifndef __JUCE_APPCONFIG_AOG7SJ__
15 | #define __JUCE_APPCONFIG_AOG7SJ__
16 |
17 | //==============================================================================
18 | // [BEGIN_USER_CODE_SECTION]
19 |
20 | // (You can add your own code in this section, and the Introjucer will not overwrite it)
21 |
22 | // [END_USER_CODE_SECTION]
23 |
24 | //==============================================================================
25 | #define JUCE_MODULE_AVAILABLE_juce_audio_basics 1
26 | #define JUCE_MODULE_AVAILABLE_juce_audio_devices 1
27 | #define JUCE_MODULE_AVAILABLE_juce_audio_formats 1
28 | #define JUCE_MODULE_AVAILABLE_juce_audio_plugin_client 1
29 | #define JUCE_MODULE_AVAILABLE_juce_audio_processors 1
30 | #define JUCE_MODULE_AVAILABLE_juce_core 1
31 | #define JUCE_MODULE_AVAILABLE_juce_cryptography 1
32 | #define JUCE_MODULE_AVAILABLE_juce_data_structures 1
33 | #define JUCE_MODULE_AVAILABLE_juce_events 1
34 | #define JUCE_MODULE_AVAILABLE_juce_graphics 1
35 | #define JUCE_MODULE_AVAILABLE_juce_gui_basics 1
36 | #define JUCE_MODULE_AVAILABLE_juce_gui_extra 1
37 | #define JUCE_MODULE_AVAILABLE_juce_opengl 1
38 | #define JUCE_MODULE_AVAILABLE_juce_video 1
39 |
40 | //==============================================================================
41 | #ifndef JUCE_STANDALONE_APPLICATION
42 | #define JUCE_STANDALONE_APPLICATION 0
43 | #endif
44 |
45 | //==============================================================================
46 | // juce_audio_devices flags:
47 |
48 | #ifndef JUCE_ASIO
49 | //#define JUCE_ASIO
50 | #endif
51 |
52 | #ifndef JUCE_WASAPI
53 | //#define JUCE_WASAPI
54 | #endif
55 |
56 | #ifndef JUCE_WASAPI_EXCLUSIVE
57 | //#define JUCE_WASAPI_EXCLUSIVE
58 | #endif
59 |
60 | #ifndef JUCE_DIRECTSOUND
61 | //#define JUCE_DIRECTSOUND
62 | #endif
63 |
64 | #ifndef JUCE_ALSA
65 | //#define JUCE_ALSA
66 | #endif
67 |
68 | #ifndef JUCE_JACK
69 | //#define JUCE_JACK
70 | #endif
71 |
72 | #ifndef JUCE_USE_ANDROID_OPENSLES
73 | //#define JUCE_USE_ANDROID_OPENSLES
74 | #endif
75 |
76 | #ifndef JUCE_USE_CDREADER
77 | //#define JUCE_USE_CDREADER
78 | #endif
79 |
80 | #ifndef JUCE_USE_CDBURNER
81 | //#define JUCE_USE_CDBURNER
82 | #endif
83 |
84 | //==============================================================================
85 | // juce_audio_formats flags:
86 |
87 | #ifndef JUCE_USE_FLAC
88 | //#define JUCE_USE_FLAC
89 | #endif
90 |
91 | #ifndef JUCE_USE_OGGVORBIS
92 | //#define JUCE_USE_OGGVORBIS
93 | #endif
94 |
95 | #ifndef JUCE_USE_MP3AUDIOFORMAT
96 | //#define JUCE_USE_MP3AUDIOFORMAT
97 | #endif
98 |
99 | #ifndef JUCE_USE_LAME_AUDIO_FORMAT
100 | //#define JUCE_USE_LAME_AUDIO_FORMAT
101 | #endif
102 |
103 | #ifndef JUCE_USE_WINDOWS_MEDIA_FORMAT
104 | //#define JUCE_USE_WINDOWS_MEDIA_FORMAT
105 | #endif
106 |
107 | //==============================================================================
108 | // juce_audio_processors flags:
109 |
110 | #ifndef JUCE_PLUGINHOST_VST
111 | //#define JUCE_PLUGINHOST_VST
112 | #endif
113 |
114 | #ifndef JUCE_PLUGINHOST_VST3
115 | //#define JUCE_PLUGINHOST_VST3
116 | #endif
117 |
118 | #ifndef JUCE_PLUGINHOST_AU
119 | //#define JUCE_PLUGINHOST_AU
120 | #endif
121 |
122 | //==============================================================================
123 | // juce_core flags:
124 |
125 | #ifndef JUCE_FORCE_DEBUG
126 | //#define JUCE_FORCE_DEBUG
127 | #endif
128 |
129 | #ifndef JUCE_LOG_ASSERTIONS
130 | //#define JUCE_LOG_ASSERTIONS
131 | #endif
132 |
133 | #ifndef JUCE_CHECK_MEMORY_LEAKS
134 | //#define JUCE_CHECK_MEMORY_LEAKS
135 | #endif
136 |
137 | #ifndef JUCE_DONT_AUTOLINK_TO_WIN32_LIBRARIES
138 | //#define JUCE_DONT_AUTOLINK_TO_WIN32_LIBRARIES
139 | #endif
140 |
141 | #ifndef JUCE_INCLUDE_ZLIB_CODE
142 | //#define JUCE_INCLUDE_ZLIB_CODE
143 | #endif
144 |
145 | #ifndef JUCE_USE_CURL
146 | //#define JUCE_USE_CURL
147 | #endif
148 |
149 | //==============================================================================
150 | // juce_graphics flags:
151 |
152 | #ifndef JUCE_USE_COREIMAGE_LOADER
153 | //#define JUCE_USE_COREIMAGE_LOADER
154 | #endif
155 |
156 | #ifndef JUCE_USE_DIRECTWRITE
157 | //#define JUCE_USE_DIRECTWRITE
158 | #endif
159 |
160 | //==============================================================================
161 | // juce_gui_basics flags:
162 |
163 | #ifndef JUCE_ENABLE_REPAINT_DEBUGGING
164 | //#define JUCE_ENABLE_REPAINT_DEBUGGING
165 | #endif
166 |
167 | #ifndef JUCE_USE_XSHM
168 | //#define JUCE_USE_XSHM
169 | #endif
170 |
171 | #ifndef JUCE_USE_XRENDER
172 | //#define JUCE_USE_XRENDER
173 | #endif
174 |
175 | #ifndef JUCE_USE_XCURSOR
176 | //#define JUCE_USE_XCURSOR
177 | #endif
178 |
179 | //==============================================================================
180 | // juce_gui_extra flags:
181 |
182 | #ifndef JUCE_WEB_BROWSER
183 | //#define JUCE_WEB_BROWSER
184 | #endif
185 |
186 | #ifndef JUCE_ENABLE_LIVE_CONSTANT_EDITOR
187 | //#define JUCE_ENABLE_LIVE_CONSTANT_EDITOR
188 | #endif
189 |
190 | //==============================================================================
191 | // juce_video flags:
192 |
193 | #ifndef JUCE_DIRECTSHOW
194 | //#define JUCE_DIRECTSHOW
195 | #endif
196 |
197 | #ifndef JUCE_MEDIAFOUNDATION
198 | //#define JUCE_MEDIAFOUNDATION
199 | #endif
200 |
201 | #ifndef JUCE_QUICKTIME
202 | #define JUCE_QUICKTIME 0
203 | #endif
204 |
205 | #ifndef JUCE_USE_CAMERA
206 | //#define JUCE_USE_CAMERA
207 | #endif
208 |
209 |
210 | //==============================================================================
211 | // Audio plugin settings..
212 |
213 | #ifndef JucePlugin_Build_VST
214 | #define JucePlugin_Build_VST 0
215 | #endif
216 | #ifndef JucePlugin_Build_VST3
217 | #define JucePlugin_Build_VST3 0
218 | #endif
219 | #ifndef JucePlugin_Build_AU
220 | #define JucePlugin_Build_AU 1
221 | #endif
222 | #ifndef JucePlugin_Build_RTAS
223 | #define JucePlugin_Build_RTAS 0
224 | #endif
225 | #ifndef JucePlugin_Build_AAX
226 | #define JucePlugin_Build_AAX 0
227 | #endif
228 | #ifndef JucePlugin_Name
229 | #define JucePlugin_Name "FilterGuiDemo"
230 | #endif
231 | #ifndef JucePlugin_Desc
232 | #define JucePlugin_Desc "FilterGuiDemo"
233 | #endif
234 | #ifndef JucePlugin_Manufacturer
235 | #define JucePlugin_Manufacturer "RudeAudio"
236 | #endif
237 | #ifndef JucePlugin_ManufacturerWebsite
238 | #define JucePlugin_ManufacturerWebsite ""
239 | #endif
240 | #ifndef JucePlugin_ManufacturerEmail
241 | #define JucePlugin_ManufacturerEmail "josh.marler@hotmail.co.uk"
242 | #endif
243 | #ifndef JucePlugin_ManufacturerCode
244 | #define JucePlugin_ManufacturerCode 'RUDE'
245 | #endif
246 | #ifndef JucePlugin_PluginCode
247 | #define JucePlugin_PluginCode 'RFil'
248 | #endif
249 | #ifndef JucePlugin_IsSynth
250 | #define JucePlugin_IsSynth 0
251 | #endif
252 | #ifndef JucePlugin_WantsMidiInput
253 | #define JucePlugin_WantsMidiInput 0
254 | #endif
255 | #ifndef JucePlugin_ProducesMidiOutput
256 | #define JucePlugin_ProducesMidiOutput 0
257 | #endif
258 | #ifndef JucePlugin_IsMidiEffect
259 | #define JucePlugin_IsMidiEffect 0
260 | #endif
261 | #ifndef JucePlugin_SilenceInProducesSilenceOut
262 | #define JucePlugin_SilenceInProducesSilenceOut 0
263 | #endif
264 | #ifndef JucePlugin_EditorRequiresKeyboardFocus
265 | #define JucePlugin_EditorRequiresKeyboardFocus 0
266 | #endif
267 | #ifndef JucePlugin_Version
268 | #define JucePlugin_Version 1.0.0
269 | #endif
270 | #ifndef JucePlugin_VersionCode
271 | #define JucePlugin_VersionCode 0x10000
272 | #endif
273 | #ifndef JucePlugin_VersionString
274 | #define JucePlugin_VersionString "1.0.0"
275 | #endif
276 | #ifndef JucePlugin_VSTUniqueID
277 | #define JucePlugin_VSTUniqueID JucePlugin_PluginCode
278 | #endif
279 | #ifndef JucePlugin_VSTCategory
280 | #define JucePlugin_VSTCategory kPlugCategEffect
281 | #endif
282 | #ifndef JucePlugin_AUMainType
283 | #define JucePlugin_AUMainType kAudioUnitType_Effect
284 | #endif
285 | #ifndef JucePlugin_AUSubType
286 | #define JucePlugin_AUSubType JucePlugin_PluginCode
287 | #endif
288 | #ifndef JucePlugin_AUExportPrefix
289 | #define JucePlugin_AUExportPrefix FilterGuiDemoAU
290 | #endif
291 | #ifndef JucePlugin_AUExportPrefixQuoted
292 | #define JucePlugin_AUExportPrefixQuoted "FilterGuiDemoAU"
293 | #endif
294 | #ifndef JucePlugin_AUManufacturerCode
295 | #define JucePlugin_AUManufacturerCode JucePlugin_ManufacturerCode
296 | #endif
297 | #ifndef JucePlugin_CFBundleIdentifier
298 | #define JucePlugin_CFBundleIdentifier com.RudeAudio.FilterGuiDemo
299 | #endif
300 | #ifndef JucePlugin_RTASCategory
301 | #define JucePlugin_RTASCategory ePlugInCategory_None
302 | #endif
303 | #ifndef JucePlugin_RTASManufacturerCode
304 | #define JucePlugin_RTASManufacturerCode JucePlugin_ManufacturerCode
305 | #endif
306 | #ifndef JucePlugin_RTASProductId
307 | #define JucePlugin_RTASProductId JucePlugin_PluginCode
308 | #endif
309 | #ifndef JucePlugin_RTASDisableBypass
310 | #define JucePlugin_RTASDisableBypass 0
311 | #endif
312 | #ifndef JucePlugin_RTASDisableMultiMono
313 | #define JucePlugin_RTASDisableMultiMono 0
314 | #endif
315 | #ifndef JucePlugin_AAXIdentifier
316 | #define JucePlugin_AAXIdentifier com.yourcompany.FilterGuiDemo
317 | #endif
318 | #ifndef JucePlugin_AAXManufacturerCode
319 | #define JucePlugin_AAXManufacturerCode JucePlugin_ManufacturerCode
320 | #endif
321 | #ifndef JucePlugin_AAXProductId
322 | #define JucePlugin_AAXProductId JucePlugin_PluginCode
323 | #endif
324 | #ifndef JucePlugin_AAXCategory
325 | #define JucePlugin_AAXCategory AAX_ePlugInCategory_Dynamics
326 | #endif
327 | #ifndef JucePlugin_AAXDisableBypass
328 | #define JucePlugin_AAXDisableBypass 0
329 | #endif
330 | #ifndef JucePlugin_AAXDisableMultiMono
331 | #define JucePlugin_AAXDisableMultiMono 0
332 | #endif
333 |
334 | #endif // __JUCE_APPCONFIG_AOG7SJ__
335 |
--------------------------------------------------------------------------------
/Source/GUIComponents/CustomLookAndFeel.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | ==============================================================================
3 |
4 | CustomLookAndFeel.cpp
5 | Created: 19 Sep 2014 7:23:32pm
6 | Author: Joshua Marler
7 |
8 | ==============================================================================
9 | */
10 |
11 | #include "CustomLookAndFeel.h"
12 |
13 |
14 | //Basic override of drawRotarySlider function
15 |
16 | /*
17 | Uses path data from SVG to path data conversion tool in Introjucer/Projucer - works best if the SVG file used is composed of a
18 | single vector / path. Change the pathData[] variable to whatever path data the SVG conversion tool spits out at you.
19 |
20 | Pay attention to this line in the drawRotarySlider function - svgPath.scaleToFit(-innerRadius, -innerRadius, innerRadius * 2.0f, innerRadius * 2.0f, true);
21 |
22 | This line scales the converted SVG path to fit inside the rotary sliders outer arc/circle. This is necessary only for this particular slider style and could be changed.
23 | */
24 |
25 | void CustomLookAndFeel::drawRotarySlider (Graphics& g, int x, int y, int width, int height, float sliderPos,
26 | const float rotaryStartAngle, const float rotaryEndAngle, Slider& slider)
27 | {
28 | const float radius = jmin (width / 2, height / 2) - 2.0f;
29 | const float centreX = x + width * 0.5f;
30 | const float centreY = y + height * 0.5f;
31 | const float rx = centreX - radius;
32 | const float ry = centreY - radius;
33 | const float rw = radius * 2.0f;
34 | const float angle = rotaryStartAngle + sliderPos * (rotaryEndAngle - rotaryStartAngle);
35 | const bool isMouseOver = slider.isMouseOverOrDragging() && slider.isEnabled();
36 |
37 | if (radius > 12.0f)
38 | {
39 | if (slider.isEnabled())
40 | g.setColour (slider.findColour (Slider::rotarySliderFillColourId).withAlpha (isMouseOver ? 1.0f : 0.7f));
41 | else
42 | g.setColour (Colour (0x80808080));
43 |
44 | const float thickness = 0.75f;
45 |
46 | {
47 | Path filledArc;
48 | filledArc.addPieSegment (rx, ry, rw, rw, rotaryStartAngle, angle, thickness);
49 |
50 | g.fillPath (filledArc);
51 | }
52 |
53 | if (thickness > 0)
54 | {
55 | const float innerRadius = radius * 0.5f;
56 | Path p;
57 |
58 |
59 | static const unsigned char pathData[] = { 110,109,102,38,152,67,154,25,94,67,98,51,115,152,67,154,25,94,67,0,192,152,67,52,51,94,67,204,12,153,67,205,76,94,67,98,102,230,152,67,205,76,94,67,204,204,152,67,205,76,94,67,204,204,152,67,205,76,94,67,98,102,166,152,67,205,76,94,67,204,12,154,67,51,
60 | 179,94,67,102,38,154,67,51,179,94,67,98,153,217,154,67,102,230,94,67,0,128,155,67,102,102,95,67,51,51,156,67,51,179,95,67,98,205,140,157,67,102,102,96,67,205,204,158,67,102,102,97,67,153,25,160,67,102,102,98,67,98,51,51,160,67,0,128,98,67,204,12,161,
61 | 67,204,76,99,67,204,76,161,67,0,128,99,67,98,50,243,161,67,51,51,100,67,204,140,162,67,102,230,100,67,50,51,163,67,154,153,101,67,98,152,89,164,67,103,230,102,67,50,115,165,67,0,128,104,67,204,140,166,67,52,51,106,67,98,255,191,166,67,103,102,106,67,
62 | 153,217,166,67,154,153,106,67,50,243,166,67,206,204,106,67,98,255,255,166,67,104,230,106,67,204,12,167,67,1,0,107,67,152,25,167,67,155,25,107,67,98,152,153,167,67,1,0,108,67,152,25,168,67,1,0,109,67,203,140,168,67,104,230,109,67,98,254,127,169,67,206,
63 | 204,111,67,101,102,170,67,206,204,113,67,254,63,171,67,2,0,116,67,98,152,89,171,67,53,51,116,67,254,255,171,67,156,25,118,67,203,12,172,67,53,51,118,67,98,101,102,172,67,207,76,119,67,254,191,172,67,2,128,120,67,152,25,173,67,53,179,121,67,98,203,204,
64 | 173,67,155,25,124,67,101,102,174,67,2,128,126,67,50,243,174,67,206,140,128,67,98,255,255,174,67,104,166,128,67,204,12,175,67,1,192,128,67,152,25,175,67,155,217,128,67,98,101,38,175,67,53,243,128,67,101,38,175,67,206,12,129,67,50,51,175,67,53,51,129,67,
65 | 98,50,115,175,67,155,217,129,67,101,166,175,67,207,140,130,67,204,204,175,67,53,51,131,67,98,50,51,176,67,155,153,132,67,50,115,176,67,104,230,133,67,50,179,176,67,155,89,135,67,98,255,191,176,67,104,166,135,67,255,191,176,67,206,204,135,67,255,191,176,
66 | 67,1,0,136,67,98,153,217,176,67,1,0,137,67,153,217,176,67,52,243,137,67,153,217,176,67,103,230,138,67,98,153,217,176,67,154,153,139,67,204,204,176,67,154,89,140,67,204,204,176,67,205,12,141,67,98,204,204,176,67,0,64,141,67,102,166,176,67,0,128,142,67,
67 | 50,179,176,67,0,128,142,67,98,255,127,176,67,102,166,143,67,255,63,176,67,205,204,144,67,255,255,175,67,102,230,145,67,98,153,217,175,67,153,153,146,67,153,153,175,67,204,76,147,67,101,102,175,67,102,230,147,67,98,152,89,175,67,204,12,148,67,50,243,174,
68 | 67,153,25,149,67,50,243,174,67,0,64,149,67,98,101,102,174,67,205,140,150,67,204,204,173,67,51,179,151,67,152,25,173,67,102,230,152,67,98,254,191,172,67,0,128,153,67,101,102,172,67,153,25,154,67,203,12,172,67,102,166,154,67,98,254,255,171,67,51,179,154,
69 | 67,49,243,171,67,204,204,154,67,101,230,171,67,153,217,154,67,98,152,217,171,67,51,243,154,67,255,191,171,67,204,12,155,67,101,166,171,67,51,51,155,67,98,152,217,170,67,205,76,156,67,50,243,169,67,205,76,157,67,255,255,168,67,205,76,158,67,98,204,140,
70 | 168,67,205,204,158,67,204,12,168,67,205,76,159,67,204,140,167,67,51,179,159,67,98,50,115,167,67,205,204,159,67,102,166,166,67,0,128,160,67,204,140,166,67,153,153,160,67,98,50,115,165,67,51,115,161,67,204,76,164,67,102,38,162,67,102,38,163,67,102,230,
71 | 162,67,98,204,140,162,67,0,64,163,67,51,243,161,67,204,140,163,67,102,102,161,67,102,230,163,67,98,51,51,161,67,0,0,164,67,204,12,161,67,204,12,164,67,51,243,160,67,153,25,164,67,98,102,230,160,67,102,38,164,67,205,204,160,67,102,38,164,67,51,179,160,
72 | 67,51,51,164,67,98,51,115,159,67,0,192,164,67,102,38,158,67,51,51,165,67,153,217,156,67,153,153,165,67,98,204,140,155,67,255,255,165,67,255,63,154,67,255,63,166,67,51,243,152,67,255,127,166,67,98,153,89,153,67,50,115,166,67,51,115,153,67,101,102,166,
73 | 67,102,102,153,67,101,102,166,67,98,0,64,153,67,101,102,166,67,153,25,152,67,203,140,166,67,0,0,152,67,203,140,166,67,98,205,12,151,67,101,166,166,67,154,25,150,67,101,166,166,67,102,38,149,67,101,166,166,67,98,204,12,149,67,101,166,166,67,0,0,149,67,
74 | 101,166,166,67,102,230,148,67,101,166,166,67,98,102,166,147,67,101,166,166,67,51,115,146,67,203,140,166,67,51,51,145,67,50,115,166,67,98,153,89,145,67,50,115,166,67,51,115,145,67,50,115,166,67,51,115,145,67,50,115,166,67,98,153,153,145,67,50,115,166,
75 | 67,51,51,144,67,255,63,166,67,153,25,144,67,255,63,166,67,98,102,102,143,67,101,38,166,67,255,191,142,67,101,230,165,67,204,12,142,67,255,191,165,67,98,255,191,140,67,101,102,165,67,50,115,139,67,101,230,164,67,102,38,138,67,101,102,164,67,98,204,12,
76 | 138,67,152,89,164,67,153,25,137,67,101,230,163,67,51,243,136,67,152,217,163,67,98,205,76,136,67,254,127,163,67,51,179,135,67,50,51,163,67,153,25,135,67,203,204,162,67,98,51,243,133,67,101,38,162,67,153,217,132,67,152,89,161,67,255,191,131,67,254,127,
77 | 160,67,98,153,153,131,67,100,102,160,67,50,115,131,67,203,76,160,67,153,89,131,67,49,51,160,67,98,204,76,131,67,100,38,160,67,255,63,131,67,151,25,160,67,102,38,131,67,203,12,160,67,98,102,166,130,67,152,153,159,67,102,38,130,67,152,25,159,67,51,179,
78 | 129,67,101,166,158,67,98,0,192,128,67,50,179,157,67,51,179,127,67,50,179,156,67,0,0,126,67,152,153,155,67,98,205,204,125,67,254,127,155,67,154,153,124,67,152,153,154,67,102,102,124,67,254,127,154,67,98,153,153,123,67,100,230,153,67,102,230,122,67,152,
79 | 89,153,67,51,51,122,67,254,191,152,67,98,205,204,120,67,203,140,151,67,153,153,119,67,152,89,150,67,0,128,118,67,203,12,149,67,98,102,102,118,67,49,243,148,67,205,76,118,67,152,217,148,67,51,51,118,67,254,191,148,67,98,153,25,118,67,100,166,148,67,153,
80 | 25,118,67,203,140,148,67,0,0,118,67,100,102,148,67,98,0,128,117,67,254,191,147,67,154,25,117,67,202,12,147,67,205,204,116,67,100,102,146,67,98,0,0,116,67,254,255,144,67,0,128,115,67,49,179,143,67,0,0,115,67,254,63,142,67,98,102,230,114,67,49,243,141,
81 | 67,102,230,114,67,203,204,141,67,102,230,114,67,152,153,141,67,98,51,179,114,67,152,153,140,67,51,179,114,67,101,166,139,67,51,179,114,67,50,179,138,67,98,51,179,114,67,255,255,137,67,205,204,114,67,255,63,137,67,205,204,114,67,204,140,136,67,98,205,
82 | 204,114,67,153,89,136,67,154,25,115,67,153,25,135,67,0,0,115,67,153,25,135,67,98,102,102,115,67,51,243,133,67,102,230,115,67,204,204,132,67,102,102,116,67,51,179,131,67,98,51,179,116,67,0,0,131,67,51,51,117,67,205,76,130,67,153,153,117,67,51,179,129,
83 | 67,98,51,179,117,67,205,140,129,67,255,127,118,67,0,128,128,67,255,127,118,67,153,89,128,67,98,153,153,119,67,152,25,126,67,204,204,120,67,204,204,123,67,50,51,122,67,101,102,121,67,98,101,230,122,67,50,51,120,67,152,153,123,67,152,25,119,67,204,76,124,
84 | 67,101,230,117,67,98,102,102,124,67,50,179,117,67,255,127,124,67,152,153,117,67,153,153,124,67,203,76,117,67,98,51,179,124,67,49,51,117,67,102,230,124,67,254,255,116,67,153,25,125,67,152,153,116,67,98,51,179,126,67,101,102,114,67,0,64,128,67,101,102,
85 | 112,67,51,51,129,67,254,127,110,67,98,102,166,129,67,254,127,109,67,102,38,130,67,254,127,108,67,102,166,130,67,49,179,107,67,98,0,192,130,67,254,127,107,67,204,140,131,67,151,25,106,67,102,166,131,67,100,230,105,67,98,0,192,132,67,49,51,104,67,102,230,
86 | 133,67,202,204,102,67,204,12,135,67,202,76,101,67,98,102,166,135,67,151,153,100,67,255,63,136,67,253,255,99,67,204,204,136,67,202,76,99,67,98,50,243,136,67,151,25,99,67,153,25,137,67,253,255,98,67,50,51,137,67,100,230,98,67,98,204,76,137,67,202,204,98,
87 | 67,152,89,137,67,202,204,98,67,50,115,137,67,49,179,98,67,98,50,179,138,67,151,153,97,67,255,255,139,67,49,179,96,67,204,76,141,67,100,230,95,67,98,153,153,142,67,151,25,95,67,102,230,143,67,151,153,94,67,50,51,145,67,151,25,94,67,98,152,217,144,67,49,
88 | 51,94,67,255,191,144,67,202,76,94,67,255,191,144,67,202,76,94,67,98,153,217,144,67,202,76,94,67,101,166,145,67,151,25,94,67,255,255,145,67,253,255,93,67,108,255,255,145,67,99,102,123,67,108,204,12,152,67,99,102,123,67,108,204,12,152,67,48,51,94,67,108,
89 | 102,38,152,67,154,25,94,67,108,102,38,152,67,154,25,94,67,99,101,0,0 };
90 |
91 |
92 | Path svgPath;
93 | svgPath.loadPathFromData (pathData, sizeof (pathData));
94 |
95 | // Fit svgpath to inner dimensions of outlineArc
96 | svgPath.scaleToFit(-innerRadius, -innerRadius, innerRadius * 2.0f, innerRadius * 2.0f, true);
97 |
98 | p.addEllipse(-innerRadius, -innerRadius, innerRadius * 2.0f, innerRadius * 2.0f);
99 | g.fillPath (svgPath, AffineTransform::rotation (angle).translated (centreX, centreY));
100 | }
101 |
102 | if (slider.isEnabled())
103 | g.setColour (slider.findColour (Slider::rotarySliderOutlineColourId));
104 | else
105 | g.setColour (Colour (0x80808080));
106 |
107 |
108 | Path outlineArc;
109 | outlineArc.addPieSegment (rx, ry, rw, rw, rotaryStartAngle, rotaryEndAngle, thickness);
110 |
111 | outlineArc.closeSubPath();
112 |
113 | g.strokePath (outlineArc, PathStrokeType (slider.isEnabled() ? (isMouseOver ? 2.0f : 1.2f) : 0.3f));
114 | }
115 |
116 | else
117 | {
118 | if (slider.isEnabled())
119 | g.setColour (slider.findColour (Slider::rotarySliderFillColourId).withAlpha
120 | (isMouseOver ? 1.0f : 0.7f));
121 | else
122 | g.setColour (Colour (0x80808080));
123 |
124 | Path p;
125 |
126 | g.fillPath (p, AffineTransform::rotation (angle).translated (centreX, centreY));
127 | }
128 | }
129 |
130 |
--------------------------------------------------------------------------------