├── .gitignore ├── LICENSE.md ├── ff_meters.cpp ├── ff_meters.h ├── LookAndFeel ├── LevelMeterLookAndFeel.h ├── SoundFieldLookAndFeelMethods.h └── LevelMeterLookAndFeelMethods.h ├── README.md ├── Visualisers ├── StereoFieldComponent.h ├── StereoFieldBuffer.h └── OutlineBuffer.h ├── LevelMeter ├── LevelMeter.cpp ├── LevelMeterSource.h └── LevelMeter.h └── Doxyfile /.gitignore: -------------------------------------------------------------------------------- 1 | .DS* 2 | html/ 3 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | ============================================================================== 2 | Copyright (c) 2017 - 2020, Foleys Finest Audio Ltd. - Daniel Walz 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, 6 | are permitted provided that the following conditions are met: 7 | 1. Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 2. Redistributions in binary form must reproduce the above copyright notice, 10 | this list of conditions and the following disclaimer in the documentation 11 | and/or other materials provided with the distribution. 12 | 3. Neither the name of the copyright holder nor the names of its contributors 13 | may be used to endorse or promote products derived from this software without 14 | specific prior written permission. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 | IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 20 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 21 | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 23 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 24 | OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 25 | OF THE POSSIBILITY OF SUCH DAMAGE. 26 | ============================================================================== 27 | 28 | -------------------------------------------------------------------------------- /ff_meters.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | ============================================================================== 3 | Copyright (c) 2017 - 2020 Foleys Finest Audio Ltd. - Daniel Walz 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without modification, 7 | are permitted provided that the following conditions are met: 8 | 1. Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 2. Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 3. Neither the name of the copyright holder nor the names of its contributors 14 | may be used to endorse or promote products derived from this software without 15 | specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 18 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 | IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 21 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 22 | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 24 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 25 | OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 26 | OF THE POSSIBILITY OF SUCH DAMAGE. 27 | ============================================================================== 28 | */ 29 | 30 | #include "ff_meters.h" 31 | 32 | #include "LevelMeter/LevelMeter.cpp" 33 | -------------------------------------------------------------------------------- /ff_meters.h: -------------------------------------------------------------------------------- 1 | /* 2 | ============================================================================== 3 | Copyright (c) 2017 - 2020 Foleys Finest Audio Ltd. - Daniel Walz 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without modification, 7 | are permitted provided that the following conditions are met: 8 | 1. Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 2. Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 3. Neither the name of the copyright holder nor the names of its contributors 14 | may be used to endorse or promote products derived from this software without 15 | specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 18 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 | IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 21 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 22 | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 24 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 25 | OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 26 | OF THE POSSIBILITY OF SUCH DAMAGE. 27 | ============================================================================== 28 | 29 | BEGIN_JUCE_MODULE_DECLARATION 30 | 31 | ID: ff_meters 32 | vendor: Foleys Finest Audio UG 33 | version: 0.9.1 34 | name: Meters with GUI and LookAndFeel 35 | description: Contains a metering Component, that can display live peak and RMS values 36 | dependencies: juce_audio_basics, juce_gui_basics, juce_events 37 | website: http://www.foleysfinest.com/ 38 | license: BSD V2 3-clause 39 | linuxLibs: m 40 | 41 | END_JUCE_MODULE_DECLARATION 42 | 43 | ============================================================================== 44 | 45 | @defgroup ff_meters 46 | 47 | This module provides a display component to show RMS, MAX and CLIP values. 48 | There is a MeterInputSource, which can process any AudioBuffer, and provide 49 | therefore the data for live display. 50 | 51 | ============================================================================== 52 | */ 53 | 54 | #pragma once 55 | 56 | #ifndef USE_FF_AUDIO_METERS 57 | #define USE_FF_AUDIO_METERS 1 58 | #endif 59 | 60 | #include 61 | #include 62 | #include 63 | 64 | #include 65 | #include 66 | #include 67 | 68 | #include "LevelMeter/LevelMeterSource.h" 69 | #include "LevelMeter/LevelMeter.h" 70 | #include "Visualisers/OutlineBuffer.h" 71 | #include "Visualisers/StereoFieldBuffer.h" 72 | #include "Visualisers/StereoFieldComponent.h" 73 | #include "LookAndFeel/LevelMeterLookAndFeel.h" 74 | 75 | // stay backwards compatible 76 | namespace FFAU=foleys; 77 | -------------------------------------------------------------------------------- /LookAndFeel/LevelMeterLookAndFeel.h: -------------------------------------------------------------------------------- 1 | /* 2 | ============================================================================== 3 | Copyright (c) 2017 - 2020 Foleys Finest Audio Ltd. - Daniel Walz 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without modification, 7 | are permitted provided that the following conditions are met: 8 | 1. Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 2. Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 3. Neither the name of the copyright holder nor the names of its contributors 14 | may be used to endorse or promote products derived from this software without 15 | specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 18 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 | IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 21 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 22 | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 24 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 25 | OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 26 | OF THE POSSIBILITY OF SUCH DAMAGE. 27 | 28 | ============================================================================== 29 | 30 | \file LevelMeterLookAndFeel.h 31 | Author: Daniel Walz 32 | 33 | ============================================================================== 34 | */ 35 | 36 | #pragma once 37 | 38 | namespace foleys 39 | { 40 | 41 | class LevelMeterSource; 42 | 43 | /** @addtogroup ff_meters */ 44 | /*@{*/ 45 | 46 | /** 47 | \class LevelMeterLookAndFeel 48 | \brief Convenience LookAndFeel which derives from LookAndFeel_V3 and LevelMeter::LookAndFeelMethods 49 | 50 | This is the shortcut, to get a component going without inheriting any LookAndFeel class. 51 | If you write your own LookAndFeel, you can include ff_meters_LookAndFeelMethods.h inside your LookAndFeel: 52 | 53 | \code{.cpp} 54 | class MyLookAndFeel : public LookAndFeel_V4, LevelMeter::LookAndFeelMethods 55 | { 56 | public: 57 | 58 | #include "ff_meters_LookAndFeelMethods.h" 59 | 60 | // ... 61 | 62 | }; 63 | \endcode 64 | */ 65 | class LevelMeterLookAndFeel : public juce::LookAndFeel_V3, public LevelMeter::LookAndFeelMethods, public StereoFieldComponent::LookAndFeelMethods 66 | { 67 | public: 68 | LevelMeterLookAndFeel () 69 | { 70 | setupDefaultMeterColours(); 71 | 72 | setupDefaultStereoFieldColours(); 73 | } 74 | 75 | virtual ~LevelMeterLookAndFeel() override {} 76 | 77 | // do this include inside the class to get the default implementation instead of copying it there 78 | #include "LevelMeterLookAndFeelMethods.h" 79 | 80 | // and the same to get the default sound field implementation instead of copying it there 81 | #include "SoundFieldLookAndFeelMethods.h" 82 | 83 | }; 84 | 85 | /*@}*/ 86 | 87 | } // end namespace foleys 88 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | ff_meters 3 | ========= 4 | 5 | by Daniel Walz / Foleys Finest Audio Ltd. 6 | Published under the BSD License (3 clause) 7 | 8 | The ff_meters provide an easy to use Component to display a level reading for an 9 | AudioBuffer. It is to be used in the audio framework JUCE (www.juce.com). 10 | 11 | Find the API documentation here: https://ffaudio.github.io/ff_meters/ 12 | 13 | 14 | Usage 15 | ===== 16 | 17 | LevelMeter 18 | ---------- 19 | 20 | To use it create a LevelMeterSource instance next to the AudioBuffer you want to 21 | display. To update the meter, call LevelMeterSource::measureBlock (buffer) in your 22 | processBlock or getNextAudioBuffer method. 23 | 24 | On the Component use LevelMeter::setMeterSource to link to the LevelMeterSource 25 | instance. The number of channels will be updated automatically. 26 | 27 | You can pull the drawing into your LookAndFeel by inheriting LevelMeter::LookAndFeelMethods 28 | and inlining the default implementation from LevelMeterLookAndFeel in 29 | ff_meters_LookAndFeelMethods.h into a public section of your class declaration. To 30 | setup the default colour scheme, call setupDefaultMeterColours() in your constructor. 31 | 32 | Or you can use the LevelMeterLookAndFeel directly because it inherits from juce::LookAndFeel_V3 33 | for your convenience. You can set it as default LookAndFeel, if you used the default, 34 | or set it only to the meters, if you don't want it to interfere. 35 | 36 | All classes are in the namespace `foleys` to avoid collisions. You can either prefix each symbol, 37 | or import the namespace. 38 | N.B. for backward compatibility, `FFAU` is an alias for `foleys`. 39 | 40 | // In your Editor 41 | public: 42 | PluginEditor() 43 | { 44 | // adjust the colours to how you like them, e.g. 45 | lnf.setColour (foleys::LevelMeter::lmMeterGradientLowColour, juce::Colours::green); 46 | 47 | meter.setLookAndFeel (&lnf); 48 | meter.setMeterSource (&processor.getMeterSource()); 49 | addAndMakeVisible (meter); 50 | // ... 51 | } 52 | ~PluginEditor() 53 | { 54 | meter.setLookAndFeel (nullptr); 55 | } 56 | 57 | private: 58 | foleys::LevelMeterLookAndFeel lnf; 59 | foleys::LevelMeter meter { foleys::LevelMeter::Minimal }; // See foleys::LevelMeter::MeterFlags for options 60 | 61 | // and in the processor: 62 | public: 63 | foleys::LevelMeterSource& getMeterSource() 64 | { 65 | return meterSource; 66 | } 67 | 68 | void prepareToPlay (double sampleRate, int samplesPerBlockExpected) override 69 | { 70 | // this prepares the meterSource to measure all output blocks and average over 100ms to allow smooth movements 71 | meterSource.resize (getTotalNumOutputChannels(), sampleRate * 0.1 / samplesPerBlockExpected); 72 | // ... 73 | } 74 | void processBlock (AudioSampleBuffer& buffer, MidiBuffer&) override 75 | { 76 | meterSource.measureBlock (buffer); 77 | // ... 78 | } 79 | 80 | private: 81 | foleys::LevelMeterSource meterSource; 82 | 83 | 84 | OutlineBuffer 85 | ------------- 86 | 87 | Another class is capable of reducing the samples going through into min and max blocks. This 88 | way you can see the outline of a signal running through. It can be used very similar: 89 | 90 | // in your processor 91 | private: 92 | foleys::OutlineBuffer outline; 93 | 94 | // in prepareToPlay 95 | outline.setSize (getTotalNumInputChannels(), 1024); 96 | 97 | // in processBlock 98 | outline.pushBlock (buffer, buffer.getNumSamples()); 99 | 100 | // and in the editor's component: 101 | const Rectangle plotFrame (10.0f, 320.0f, 580f, 80f); 102 | g.setColour (Colours::lightgreen); 103 | g.fillRect (plotFrame); 104 | 105 | Path plot; 106 | processor.getChannelOutline (plot, plotFrame, 1000); 107 | g.setColour (Colours::grey); 108 | g.fillPath (plot); 109 | g.setColour (Colours::black); 110 | g.strokePath (plot, PathStrokeType (1.0f)); 111 | 112 | 113 | ******************************************************************************** 114 | 115 | We hope it is of any use, let us know of any problems or improvements you may 116 | come up with... 117 | 118 | Brighton, 2nd March 2017 119 | 120 | ******************************************************************************** 121 | -------------------------------------------------------------------------------- /Visualisers/StereoFieldComponent.h: -------------------------------------------------------------------------------- 1 | /* 2 | ============================================================================== 3 | Copyright (c) 2018-2020 Foleys Finest Audio Ltd. - Daniel Walz 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without modification, 7 | are permitted provided that the following conditions are met: 8 | 1. Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 2. Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 3. Neither the name of the copyright holder nor the names of its contributors 14 | may be used to endorse or promote products derived from this software without 15 | specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 18 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 | IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 21 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 22 | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 24 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 25 | OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 26 | OF THE POSSIBILITY OF SUCH DAMAGE. 27 | 28 | ============================================================================== 29 | 30 | StereoFieldComponent.h 31 | Created: 2 Jan 2018 00:16:54pm 32 | Author: Daniel Walz 33 | 34 | ============================================================================== 35 | */ 36 | 37 | #pragma once 38 | 39 | 40 | namespace foleys 41 | { 42 | 43 | /** @addtogroup ff_meters */ 44 | /*@{*/ 45 | 46 | /** 47 | \class StereoFieldComponent 48 | 49 | This class implements a circular buffer to buffer audio samples. 50 | At any time the GUI can ask for a stereo field visualisation of 51 | two neightbouring channels. 52 | */ 53 | class StereoFieldComponent : public juce::Component 54 | { 55 | public: 56 | enum 57 | { 58 | GonioMeter = 0, 59 | StereoField 60 | }; 61 | 62 | enum ColourIds 63 | { 64 | backgroundColour = 0x2200101, /**< Colour for the numbers etc. */ 65 | borderColour, /**< Colour for the numbers etc. */ 66 | outlineColour, /**< Colour for the numbers etc. */ 67 | gonioColour, /**< Colour for the numbers etc. */ 68 | currentValuesColour, /**< Colour for the numbers etc. */ 69 | maxValuesColour /**< Colour for the numbers etc. */ 70 | }; 71 | 72 | class LookAndFeelMethods 73 | { 74 | public: 75 | virtual ~LookAndFeelMethods() {} 76 | 77 | virtual void setupDefaultStereoFieldColours () = 0; 78 | 79 | virtual void drawGonioBackground (juce::Graphics& g, juce::Rectangle bounds, float margin, float border) = 0; 80 | 81 | virtual void drawGonioMeter (juce::Graphics& g, 82 | juce::Rectangle bounds, 83 | const StereoFieldBuffer& stereoBuffer, 84 | int leftIdx, int rightIdx) = 0; 85 | 86 | virtual void drawStereoFieldBackground (juce::Graphics& g, juce::Rectangle bounds, float margin, float border) = 0; 87 | 88 | virtual void drawStereoField (juce::Graphics& g, 89 | juce::Rectangle bounds, 90 | const StereoFieldBuffer&, 91 | int leftIdx = 0, int rightIdx = 1) = 0; 92 | }; 93 | 94 | StereoFieldComponent (StereoFieldBuffer& stereo) 95 | : stereoBuffer (stereo) 96 | { 97 | } 98 | 99 | void paint (juce::Graphics& g) override 100 | { 101 | juce::Graphics::ScopedSaveState saved (g); 102 | 103 | if (auto* lnf = dynamic_cast (&getLookAndFeel())) 104 | { 105 | if (type == GonioMeter) 106 | { 107 | auto bounds = getLocalBounds().toFloat(); 108 | lnf->drawGonioBackground (g, bounds, margin, border); 109 | lnf->drawGonioMeter (g, bounds.reduced (margin), stereoBuffer, 0, 1); 110 | } 111 | else if (type == StereoField) 112 | { 113 | auto bounds = getLocalBounds().toFloat(); 114 | lnf->drawStereoFieldBackground (g, bounds, margin, border); 115 | lnf->drawStereoField (g, bounds.reduced (margin), stereoBuffer, 0, 1); 116 | } 117 | } 118 | else 119 | { 120 | // This LookAndFeel is missing the StereoFieldComponent::LookAndFeelMethods. 121 | // If you work with the default LookAndFeel, set an instance of 122 | // LevelMeterLookAndFeel as LookAndFeel of this component. 123 | // 124 | // If you write a LookAndFeel from scratch, inherit also 125 | // StereoFieldComponent::LookAndFeelMethods 126 | jassertfalse; 127 | } 128 | 129 | } 130 | 131 | private: 132 | StereoFieldBuffer& stereoBuffer; 133 | int type = GonioMeter; 134 | 135 | float margin = 5.0f; 136 | float border = 2.0f; 137 | 138 | JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (StereoFieldComponent) 139 | 140 | 141 | }; 142 | /*@}*/ 143 | } 144 | -------------------------------------------------------------------------------- /LookAndFeel/SoundFieldLookAndFeelMethods.h: -------------------------------------------------------------------------------- 1 | /* 2 | ============================================================================== 3 | Copyright (c) 2018-2020 Foleys Finest Audio Ltd. - Daniel Walz 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without modification, 7 | are permitted provided that the following conditions are met: 8 | 1. Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 2. Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 3. Neither the name of the copyright holder nor the names of its contributors 14 | may be used to endorse or promote products derived from this software without 15 | specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 18 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 | IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 21 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 22 | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 24 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 25 | OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 26 | OF THE POSSIBILITY OF SUCH DAMAGE. 27 | 28 | ============================================================================== 29 | 30 | \file SoundFieldLookAndFeelMethods.h 31 | Author: Daniel Walz 32 | 33 | To use the default implementation of your SoundField in your LookAndFeel, 34 | inherit your LookAndFeel class from SoundField::LookAndFeelMethods and 35 | include this file inside your class declaration in a public section. 36 | 37 | In the Constructor you might want to call setupDefaultMeterColours() to 38 | setup the default colour scheme. 39 | ============================================================================== 40 | */ 41 | 42 | 43 | // include this file inside the implementation of your LookAndFeel to get the default implementation instead of copying it there 44 | 45 | void setupDefaultStereoFieldColours () override 46 | { 47 | setColour (StereoFieldComponent::backgroundColour, juce::Colour (0xff050a29)); 48 | setColour (StereoFieldComponent::borderColour, juce::Colours::silver); 49 | setColour (StereoFieldComponent::outlineColour, juce::Colours::silver); 50 | setColour (StereoFieldComponent::gonioColour, juce::Colours::silver); 51 | setColour (StereoFieldComponent::currentValuesColour, juce::Colours::silver); 52 | setColour (StereoFieldComponent::maxValuesColour, juce::Colours::darkgrey); 53 | } 54 | 55 | void drawGonioBackground (juce::Graphics& g, juce::Rectangle bounds, float margin, float border) override 56 | { 57 | auto colour = findColour (StereoFieldComponent::backgroundColour); 58 | g.fillAll (colour); 59 | colour = findColour (StereoFieldComponent::borderColour); 60 | g.setColour (colour); 61 | g.drawRoundedRectangle (bounds.reduced (margin * 0.5f), margin * 0.5f, border); 62 | 63 | colour = findColour (StereoFieldComponent::outlineColour); 64 | g.setColour (colour); 65 | auto size = std::min (bounds.getWidth(), bounds.getHeight()); 66 | auto oscBounds = bounds.withSizeKeepingCentre (size, size).reduced (10); 67 | g.drawEllipse (oscBounds.toFloat(), 1.0); 68 | } 69 | 70 | void drawGonioMeter (juce::Graphics& g, 71 | juce::Rectangle bounds, 72 | const StereoFieldBuffer& stereoBuffer, 73 | int leftIdx, int rightIdx) override 74 | { 75 | auto colour = findColour (StereoFieldComponent::gonioColour); 76 | g.setColour (colour); 77 | 78 | auto size = std::min (bounds.getWidth(), bounds.getHeight()); 79 | auto oscBounds = bounds.withSizeKeepingCentre (size, size); 80 | auto osciloscope = stereoBuffer.getOscilloscope (512, oscBounds.toFloat(), leftIdx, rightIdx); 81 | g.strokePath (osciloscope, juce::PathStrokeType (1.0)); 82 | } 83 | 84 | void drawStereoFieldBackground (juce::Graphics& g, juce::Rectangle bounds, float margin, float border) override 85 | { 86 | g.drawRoundedRectangle (bounds.reduced (margin * 0.5f), margin * 0.5f, border); 87 | auto graph = bounds.reduced (margin); 88 | juce::Path background; 89 | background.addRectangle (graph); 90 | background.addCentredArc (graph.getCentreX(), graph.getBottom(), 91 | 0.5f * graph.getWidth(), 0.5f * graph.getWidth(), 92 | 0.0f, 1.5f * juce::MathConstants::pi, 2.5f * juce::MathConstants::pi); 93 | background.addCentredArc (graph.getCentreX(), graph.getBottom(), 94 | 0.25f * graph.getWidth(), 0.25f * graph.getWidth(), 95 | 0.0f, 1.5f * juce::MathConstants::pi, 2.5f * juce::MathConstants::pi); 96 | const auto d = graph.getWidth() * 0.5f / std::sqrt (2.0f); 97 | background.addLineSegment (juce::Line (graph.getCentreX(), graph.getBottom(), 98 | graph.getCentreX() - d, graph.getBottom() - d), 1.0f); 99 | background.addLineSegment (juce::Line (graph.getCentreX(), graph.getBottom(), 100 | graph.getCentreX(), graph.getBottom() - graph.getWidth() * 0.5f), 1.0f); 101 | background.addLineSegment (juce::Line (graph.getCentreX(), graph.getBottom(), 102 | graph.getCentreX() + d, graph.getBottom() - d), 1.0f); 103 | g.strokePath (background, juce::PathStrokeType (1.0)); 104 | 105 | } 106 | 107 | void drawStereoField ([[maybe_unused]] juce::Graphics& g, 108 | [[maybe_unused]] juce::Rectangle bounds, 109 | [[maybe_unused]] const StereoFieldBuffer&, 110 | [[maybe_unused]] int leftIdx = 0, 111 | [[maybe_unused]] int rightIdx = 1) override 112 | { 113 | juce::ignoreUnused (g); 114 | juce::ignoreUnused (bounds); 115 | juce::ignoreUnused (leftIdx, rightIdx); 116 | } 117 | 118 | -------------------------------------------------------------------------------- /LevelMeter/LevelMeter.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | ============================================================================== 3 | Copyright (c) 2017 - 2020 Foleys Finest Audio Ltd. - Daniel Walz 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without modification, 7 | are permitted provided that the following conditions are met: 8 | 1. Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 2. Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 3. Neither the name of the copyright holder nor the names of its contributors 14 | may be used to endorse or promote products derived from this software without 15 | specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 18 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 | IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 21 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 22 | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 24 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 25 | OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 26 | OF THE POSSIBILITY OF SUCH DAMAGE. 27 | 28 | ============================================================================== 29 | 30 | LevelMeter.cpp 31 | Created: 5 Apr 2016 9:49:54am 32 | Author: Daniel Walz 33 | 34 | ============================================================================== 35 | */ 36 | 37 | namespace foleys 38 | { 39 | 40 | LevelMeter::LevelMeter (MeterFlags type) 41 | : meterType (type) 42 | { 43 | lookAndFeelChanged(); 44 | 45 | onMaxLevelClicked = [](FFAU::LevelMeter& meter, [[maybe_unused]] int channel, [[maybe_unused]] juce::ModifierKeys mods) 46 | { 47 | // default clear all indicators. Overwrite this lambda to change the behaviour 48 | meter.clearMaxLevelDisplay(); 49 | meter.clearClipIndicator(); 50 | }; 51 | 52 | onClipLightClicked = [](FFAU::LevelMeter& meter, [[maybe_unused]] int channel, [[maybe_unused]] juce::ModifierKeys mods) 53 | { 54 | // default clear all indicators. Overwrite this lambda to change the behaviour 55 | meter.clearMaxLevelDisplay(); 56 | meter.clearClipIndicator(); 57 | }; 58 | 59 | startTimerHz (refreshRate); 60 | } 61 | 62 | LevelMeter::~LevelMeter() 63 | { 64 | stopTimer(); 65 | } 66 | 67 | void LevelMeter::setMeterFlags (MeterFlags type) 68 | { 69 | meterType = type; 70 | } 71 | 72 | void LevelMeter::setMeterSource (LevelMeterSource* src) 73 | { 74 | source = src; 75 | repaint(); 76 | } 77 | 78 | void LevelMeter::setSelectedChannel (int c) 79 | { 80 | selectedChannel = c; 81 | } 82 | 83 | void LevelMeter::setFixedNumChannels (int numChannels) 84 | { 85 | fixedNumChannels = numChannels; 86 | } 87 | 88 | void LevelMeter::setRefreshRateHz (int newRefreshRate) 89 | { 90 | refreshRate = newRefreshRate; 91 | startTimerHz (refreshRate); 92 | } 93 | 94 | void LevelMeter::paint (juce::Graphics& g) 95 | { 96 | juce::Graphics::ScopedSaveState saved (g); 97 | 98 | const juce::Rectangle bounds = getLocalBounds().toFloat(); 99 | int numChannels = source ? source->getNumChannels() : 1; 100 | if (useBackgroundImage) 101 | { 102 | // This seems to only speed up, if you use complex drawings on the background. For 103 | // "normal" vector graphics the image approach seems actually slower 104 | if (backgroundNeedsRepaint) 105 | { 106 | backgroundImage = juce::Image (juce::Image::ARGB, getWidth(), getHeight(), true); 107 | juce::Graphics backGraphics (backgroundImage); 108 | lmLookAndFeel->drawBackground (backGraphics, meterType, bounds); 109 | lmLookAndFeel->drawMeterBarsBackground (backGraphics, meterType, bounds, numChannels, fixedNumChannels); 110 | backgroundNeedsRepaint = false; 111 | } 112 | g.drawImageAt (backgroundImage, 0, 0); 113 | lmLookAndFeel->drawMeterBars (g, meterType, bounds, source, fixedNumChannels, selectedChannel); 114 | } 115 | else 116 | { 117 | lmLookAndFeel->drawBackground (g, meterType, bounds); 118 | lmLookAndFeel->drawMeterBarsBackground (g, meterType, bounds, numChannels, fixedNumChannels); 119 | lmLookAndFeel->drawMeterBars (g, meterType, bounds, source, fixedNumChannels, selectedChannel); 120 | } 121 | 122 | if (source) 123 | { 124 | source->decayIfNeeded(); 125 | } 126 | } 127 | 128 | void LevelMeter::resized () 129 | { 130 | lmLookAndFeel->updateMeterGradients(); 131 | backgroundNeedsRepaint = true; 132 | } 133 | 134 | void LevelMeter::visibilityChanged () 135 | { 136 | backgroundNeedsRepaint = true; 137 | } 138 | 139 | void LevelMeter::timerCallback () 140 | { 141 | if ((source && source->checkNewDataFlag()) || backgroundNeedsRepaint) 142 | { 143 | if (source) 144 | source->resetNewDataFlag(); 145 | 146 | repaint(); 147 | } 148 | } 149 | 150 | void LevelMeter::clearClipIndicator (int channel) 151 | { 152 | if (source == nullptr) 153 | return; 154 | 155 | if (channel < 0) 156 | source->clearAllClipFlags(); 157 | else 158 | source->clearClipFlag (channel); 159 | } 160 | 161 | void LevelMeter::clearMaxLevelDisplay (int channel) 162 | { 163 | if (source == nullptr) 164 | return; 165 | 166 | if (channel < 0) 167 | source->clearAllMaxNums(); 168 | else 169 | source->clearMaxNum (channel); 170 | } 171 | 172 | void LevelMeter::mouseDown (const juce::MouseEvent &event) 173 | { 174 | if (source == nullptr) 175 | return; 176 | 177 | const juce::Rectangle innerBounds = lmLookAndFeel->getMeterInnerBounds (getLocalBounds().toFloat(), 178 | meterType); 179 | if (event.mods.isLeftButtonDown()) 180 | { 181 | auto channel = lmLookAndFeel->hitTestClipIndicator (event.getPosition(), 182 | meterType, 183 | innerBounds, 184 | source); 185 | if (channel >= 0) 186 | { 187 | listeners.call (&LevelMeter::Listener::clipLightClicked, this, channel, event.mods); 188 | if (onClipLightClicked) 189 | onClipLightClicked (*this, channel, event.mods); 190 | } 191 | 192 | channel = lmLookAndFeel->hitTestMaxNumber (event.getPosition(), 193 | meterType, 194 | innerBounds, 195 | source); 196 | if (channel >= 0) 197 | { 198 | listeners.call (&LevelMeter::Listener::maxLevelClicked, this, channel, event.mods); 199 | if (onMaxLevelClicked) 200 | onMaxLevelClicked (*this, channel, event.mods); 201 | } 202 | } 203 | } 204 | 205 | void LevelMeter::addListener (LevelMeter::Listener* listener) 206 | { 207 | listeners.add (listener); 208 | } 209 | 210 | void LevelMeter::removeListener (LevelMeter::Listener* listener) 211 | { 212 | listeners.remove (listener); 213 | } 214 | 215 | void LevelMeter::parentHierarchyChanged() 216 | { 217 | lookAndFeelChanged(); 218 | } 219 | 220 | void LevelMeter::lookAndFeelChanged() 221 | { 222 | if (auto* lnf = dynamic_cast (&getLookAndFeel())) 223 | { 224 | lmLookAndFeel = lnf; 225 | fallbackLookAndFeel.reset(); 226 | } 227 | else 228 | { 229 | if (fallbackLookAndFeel.get() == nullptr) 230 | fallbackLookAndFeel = std::make_unique(); 231 | 232 | lmLookAndFeel = fallbackLookAndFeel.get(); 233 | } 234 | } 235 | 236 | } // namespace foleys 237 | -------------------------------------------------------------------------------- /Visualisers/StereoFieldBuffer.h: -------------------------------------------------------------------------------- 1 | /* 2 | ============================================================================== 3 | Copyright (c) 2018-2020 Foleys Finest Audio Ltd. - Daniel Walz 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without modification, 7 | are permitted provided that the following conditions are met: 8 | 1. Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 2. Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 3. Neither the name of the copyright holder nor the names of its contributors 14 | may be used to endorse or promote products derived from this software without 15 | specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 18 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 | IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 21 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 22 | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 24 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 25 | OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 26 | OF THE POSSIBILITY OF SUCH DAMAGE. 27 | 28 | ============================================================================== 29 | 30 | StereoFieldBuffer.h 31 | Created: 29 Dec 2017 16:49:54pm 32 | Author: Daniel Walz 33 | 34 | ============================================================================== 35 | */ 36 | 37 | #pragma once 38 | 39 | namespace foleys 40 | { 41 | 42 | /** @addtogroup ff_meters */ 43 | /*@{*/ 44 | 45 | /** 46 | \class StereoFieldBuffer 47 | 48 | This class implements a circular buffer to buffer audio samples. 49 | At any time the GUI can ask for a stereo field visualisation of 50 | two neightbouring channels. 51 | */ 52 | template 53 | class StereoFieldBuffer 54 | { 55 | juce::AudioBuffer sampleBuffer; 56 | std::atomic writePosition = { 0 }; 57 | std::vector maxValues = { 180, 0.0 }; 58 | 59 | JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (StereoFieldBuffer) 60 | 61 | inline void computeDirection (std::vector& directions, const FloatType left, const FloatType right) const 62 | { 63 | if (left == 0) 64 | { 65 | directions [45] = std::max (directions [45], std::abs (right)); 66 | } 67 | else if (left * right > 0) 68 | { 69 | 70 | } 71 | 72 | } 73 | 74 | inline juce::Point computePosition (const juce::Rectangle& b, const FloatType left, const FloatType right) const 75 | { 76 | return juce::Point (b.getCentreX() + FloatType (0.5) * b.getWidth() * (right - left), 77 | b.getCentreY() + FloatType (0.5) * b.getHeight() * (left + right)); 78 | } 79 | 80 | public: 81 | StereoFieldBuffer () 82 | { 83 | } 84 | 85 | void setBufferSize (int newNumChannels, int newNumSamples) 86 | { 87 | sampleBuffer.setSize (newNumChannels, newNumSamples); 88 | sampleBuffer.clear(); 89 | writePosition = 0; 90 | } 91 | 92 | void pushSampleBlock (juce::AudioBuffer buffer, int numSamples) 93 | { 94 | jassert (buffer.getNumChannels() == sampleBuffer.getNumChannels()); 95 | 96 | auto pos = writePosition.load(); 97 | auto space = sampleBuffer.getNumSamples() - pos; 98 | if (space >= numSamples) { 99 | for (int c=0; c < sampleBuffer.getNumChannels(); ++c) { 100 | sampleBuffer.copyFrom (c, pos, buffer.getReadPointer(c), numSamples); 101 | } 102 | writePosition = pos + numSamples; 103 | } 104 | else { 105 | for (int c=0; c < sampleBuffer.getNumChannels(); ++c) { 106 | sampleBuffer.copyFrom (c, pos, buffer.getReadPointer(c), space); 107 | sampleBuffer.copyFrom (c, 0, buffer.getReadPointer(c, space), numSamples - space); 108 | } 109 | writePosition = numSamples - space; 110 | } 111 | } 112 | 113 | void resetMaxValues () 114 | { 115 | std::fill (maxValues.begin(), maxValues.end(), 0.0); 116 | } 117 | 118 | // ============================================================================== 119 | 120 | juce::Path getOscilloscope (const int numSamples, const juce::Rectangle bounds, int leftIdx, int rightIdx) const 121 | { 122 | juce::Path curve; 123 | auto pos = writePosition.load(); 124 | if (pos >= numSamples) 125 | { 126 | auto* left = sampleBuffer.getReadPointer (leftIdx, pos - numSamples); 127 | auto* right = sampleBuffer.getReadPointer (rightIdx, pos - numSamples); 128 | curve.startNewSubPath (computePosition (bounds, *left, *right)); 129 | ++left; ++right; 130 | for (int i=1; i < numSamples; ++i) { 131 | curve.lineTo (computePosition (bounds, *left, *right)); 132 | ++left; ++right; 133 | } 134 | } 135 | else 136 | { 137 | auto leftover = numSamples - pos; 138 | auto* left = sampleBuffer.getReadPointer (leftIdx, sampleBuffer.getNumSamples() - leftover); 139 | auto* right = sampleBuffer.getReadPointer (rightIdx, sampleBuffer.getNumSamples() - leftover); 140 | curve.startNewSubPath (computePosition (bounds, *left, *right)); 141 | ++left; ++right; 142 | for (int i=1; i < leftover; ++i) { 143 | curve.lineTo (computePosition (bounds, *left, *right)); 144 | ++left; ++right; 145 | } 146 | left = sampleBuffer.getReadPointer (leftIdx); 147 | right = sampleBuffer.getReadPointer (rightIdx); 148 | for (int i=0; i < numSamples - leftover; ++i) { 149 | curve.lineTo (computePosition (bounds, *left, *right)); 150 | ++left; ++right; 151 | } 152 | } 153 | 154 | return curve; 155 | } 156 | 157 | 158 | // ============================================================================== 159 | 160 | void getDirections (std::vector& directions, int numSamples, int leftIdx, int rightIdx) 161 | { 162 | jassert (directions.size() == 180); 163 | std::fill (directions.begin(), directions.end(), 0.0); 164 | auto pos = writePosition.load(); 165 | 166 | if (pos >= numSamples) 167 | { 168 | auto* left = sampleBuffer.getReadPointer (leftIdx, pos - numSamples); 169 | auto* right = sampleBuffer.getReadPointer (rightIdx, pos - numSamples); 170 | for (int i=0; i < numSamples; ++i) { 171 | computeDirection (directions, *left, *right); 172 | ++left; ++right; 173 | } 174 | } 175 | else 176 | { 177 | auto leftover = numSamples - pos; 178 | auto* left = sampleBuffer.getReadPointer (leftIdx, sampleBuffer.getNumSamples() - leftover); 179 | auto* right = sampleBuffer.getReadPointer (rightIdx, sampleBuffer.getNumSamples() - leftover); 180 | for (int i=0; i < leftover; ++i) { 181 | computeDirection (directions, *left, *right); 182 | ++left; ++right; 183 | } 184 | left = sampleBuffer.getReadPointer (leftIdx); 185 | right = sampleBuffer.getReadPointer (rightIdx); 186 | for (int i=0; i < numSamples - leftover; ++i) { 187 | computeDirection (directions, *left, *right); 188 | ++left; ++right; 189 | } 190 | } 191 | } 192 | 193 | }; 194 | /*@}*/ 195 | } 196 | -------------------------------------------------------------------------------- /Visualisers/OutlineBuffer.h: -------------------------------------------------------------------------------- 1 | /* 2 | ============================================================================== 3 | Copyright (c) 2017 - 2020 Foleys Finest Audio Ltd. - Daniel Walz 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without modification, 7 | are permitted provided that the following conditions are met: 8 | 1. Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 2. Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 3. Neither the name of the copyright holder nor the names of its contributors 14 | may be used to endorse or promote products derived from this software without 15 | specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 18 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 | IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 21 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 22 | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 24 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 25 | OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 26 | OF THE POSSIBILITY OF SUCH DAMAGE. 27 | 28 | ============================================================================== 29 | 30 | OutlineBuffer.h 31 | Created: 9 Sep 2017 16:49:54pm 32 | Author: Daniel Walz 33 | 34 | ============================================================================== 35 | */ 36 | 37 | #pragma once 38 | 39 | namespace foleys 40 | { 41 | 42 | /** @addtogroup ff_meters */ 43 | /*@{*/ 44 | 45 | /** 46 | \class OutlineBuffer 47 | 48 | This class implements a circular buffer to store min and max values 49 | of anaudio signal. The block size can be specified. At any time the 50 | UI can request an outline of the last n blocks as Path to fill or stroke 51 | */ 52 | class OutlineBuffer 53 | { 54 | 55 | class ChannelData 56 | { 57 | std::vector minBuffer; 58 | std::vector maxBuffer; 59 | std::atomic writePointer {0}; 60 | int fraction = 0; 61 | int samplesPerBlock = 128; 62 | 63 | JUCE_LEAK_DETECTOR (ChannelData) 64 | public: 65 | ChannelData () 66 | { 67 | setSize (1024); 68 | } 69 | 70 | /** 71 | This copy constructor does not really copy. It is only present to satisfy the vector. 72 | */ 73 | ChannelData (const ChannelData& other) 74 | { 75 | setSize (other.getSize()); 76 | } 77 | 78 | /** 79 | @return the number of values the buffer will store. 80 | */ 81 | int getSize () const 82 | { 83 | return static_cast (minBuffer.size()); 84 | } 85 | 86 | void setSamplesPerBlock (const int numSamples) 87 | { 88 | samplesPerBlock = numSamples; 89 | } 90 | 91 | /** 92 | @param numBlocks is the number of values the buffer will store. Allow a little safety buffer, so you 93 | don't write into the part, where it is currently read 94 | */ 95 | void setSize (const int numBlocks) 96 | { 97 | minBuffer.resize (size_t (numBlocks), 0.0f); 98 | maxBuffer.resize (size_t (numBlocks), 0.0f); 99 | writePointer = writePointer % size_t (numBlocks); 100 | } 101 | 102 | void pushChannelData (const float* input, const int numSamples) 103 | { 104 | // create peak values 105 | int samples = 0; 106 | juce::Range minMax; 107 | while (samples < numSamples) 108 | { 109 | auto leftover = numSamples - samples; 110 | if (fraction > 0) 111 | { 112 | minMax = juce::FloatVectorOperations::findMinAndMax (input, samplesPerBlock - fraction); 113 | maxBuffer [(size_t) writePointer] = std::max (maxBuffer [(size_t) writePointer], minMax.getEnd()); 114 | minBuffer [(size_t) writePointer] = std::min (minBuffer [(size_t) writePointer], minMax.getStart()); 115 | samples += samplesPerBlock - fraction; 116 | fraction = 0; 117 | writePointer = (writePointer + 1) % maxBuffer.size(); 118 | } 119 | else if (leftover > samplesPerBlock) 120 | { 121 | minMax = juce::FloatVectorOperations::findMinAndMax (input + samples, samplesPerBlock); 122 | maxBuffer [(size_t) writePointer] = minMax.getEnd(); 123 | minBuffer [(size_t) writePointer] = minMax.getStart(); 124 | samples += samplesPerBlock; 125 | writePointer = (writePointer + 1) % maxBuffer.size(); 126 | } 127 | else 128 | { 129 | minMax = juce::FloatVectorOperations::findMinAndMax (input + samples, leftover); 130 | maxBuffer [(size_t) writePointer] = minMax.getEnd(); 131 | minBuffer [(size_t) writePointer] = minMax.getStart(); 132 | samples += samplesPerBlock - fraction; 133 | fraction = leftover; 134 | } 135 | jassert (minMax.getStart() == minMax.getStart() && minMax.getEnd() == minMax.getEnd()); 136 | } 137 | } 138 | 139 | void getChannelOutline (juce::Path& outline, const juce::Rectangle bounds, const int numSamplesToPlot) const 140 | { 141 | auto numSamples = size_t (numSamplesToPlot); 142 | auto latest = writePointer > 0 ? writePointer - 1 : maxBuffer.size() - 1; 143 | auto oldest = (latest >= numSamples) ? latest - numSamples : latest + maxBuffer.size() - numSamples; 144 | 145 | const auto dx = bounds.getWidth() / numSamples; 146 | const auto dy = bounds.getHeight() * 0.35f; 147 | const auto my = bounds.getCentreY(); 148 | auto x = bounds.getX(); 149 | auto s = oldest; 150 | 151 | outline.startNewSubPath (x, my); 152 | for (size_t i=0; i < numSamples; ++i) 153 | { 154 | outline.lineTo (x, my + minBuffer [s] * dy); 155 | x += dx; 156 | if (s < minBuffer.size() - 1) 157 | s += 1; 158 | else 159 | s = 0; 160 | } 161 | 162 | for (size_t i=0; i < numSamples; ++i) 163 | { 164 | outline.lineTo (x, my + maxBuffer [s] * dy); 165 | x -= dx; 166 | if (s > 1) 167 | s -= 1; 168 | else 169 | s = maxBuffer.size() - 1; 170 | } 171 | } 172 | }; 173 | 174 | std::vector channelDatas; 175 | int samplesPerBlock = 128; 176 | 177 | 178 | JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(OutlineBuffer) 179 | public: 180 | OutlineBuffer () 181 | { 182 | } 183 | 184 | /** 185 | @param numChannels is the number of channels the buffer will store 186 | @param numBlocks is the number of values the buffer will store. Allow a little safety buffer, so you 187 | don't write into the part, where it is currently read 188 | */ 189 | void setSize (const int numChannels, const int numBlocks) 190 | { 191 | channelDatas.resize (size_t (numChannels)); 192 | for (auto& data : channelDatas) { 193 | data.setSize (numBlocks); 194 | data.setSamplesPerBlock (samplesPerBlock); 195 | } 196 | } 197 | 198 | /** 199 | @param numSamples sets the size of each analysed block 200 | */ 201 | void setSamplesPerBlock (const int numSamples) 202 | { 203 | samplesPerBlock = numSamples; 204 | for (auto& data : channelDatas) 205 | data.setSamplesPerBlock (numSamples); 206 | } 207 | 208 | /** 209 | Push a block of audio samples into the outline buffer. 210 | */ 211 | void pushBlock (const juce::AudioBuffer& buffer, const int numSamples) 212 | { 213 | for (int i=0; i < buffer.getNumChannels(); ++i) { 214 | if (i < int (channelDatas.size())) { 215 | channelDatas [size_t (i)].pushChannelData (buffer.getReadPointer (i), numSamples); 216 | } 217 | } 218 | } 219 | 220 | /** 221 | Returns the outline of a specific channel inside the bounds. 222 | @param path is a Path to be populated 223 | @param bounds the rectangle to paint within. The result is not clipped, if samples are exceeding 1.0, it may paint outside 224 | @param channel the index of the channel to paint 225 | @param numSamples is the number of sample blocks 226 | @return a path with a single channel outline (min to max) 227 | */ 228 | void getChannelOutline (juce::Path& path, const juce::Rectangle bounds, const int channel, const int numSamples) const 229 | { 230 | if (channel < int (channelDatas.size())) 231 | return channelDatas [size_t (channel)].getChannelOutline (path, bounds, numSamples); 232 | } 233 | 234 | /** 235 | This returns the outlines of each channel, splitting the bounds into equal sized rows 236 | @param path is a Path to be populated 237 | @param bounds the rectangle to paint within. The result is not clipped, if samples are exceeding 1.0, it may paint outside 238 | @param numSamples is the number of sample blocks 239 | @return a path with a single channel outline (min to max) 240 | */ 241 | void getChannelOutline (juce::Path& path, const juce::Rectangle bounds, const int numSamples) const 242 | { 243 | juce::Rectangle b (bounds); 244 | const int numChannels = static_cast (channelDatas.size()); 245 | const float h = bounds.getHeight() / numChannels; 246 | 247 | for (int i=0; i < numChannels; ++i) { 248 | getChannelOutline (path, b.removeFromTop (h) , i, numSamples); 249 | } 250 | } 251 | 252 | 253 | }; 254 | /*@}*/ 255 | } 256 | -------------------------------------------------------------------------------- /LevelMeter/LevelMeterSource.h: -------------------------------------------------------------------------------- 1 | /* 2 | ============================================================================== 3 | Copyright (c) 2017 - 2020 Foleys Finest Audio Ltd. - Daniel Walz 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without modification, 7 | are permitted provided that the following conditions are met: 8 | 1. Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 2. Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 3. Neither the name of the copyright holder nor the names of its contributors 14 | may be used to endorse or promote products derived from this software without 15 | specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 18 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 | IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 21 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 22 | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 24 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 25 | OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 26 | OF THE POSSIBILITY OF SUCH DAMAGE. 27 | 28 | ============================================================================== 29 | 30 | LevelMeterSource.h 31 | Created: 5 Apr 2016 9:49:54am 32 | Author: Daniel Walz 33 | 34 | ============================================================================== 35 | */ 36 | 37 | #pragma once 38 | 39 | namespace foleys 40 | { 41 | 42 | /** @addtogroup ff_meters */ 43 | /*@{*/ 44 | 45 | /** 46 | \class LevelMeterSource 47 | 48 | To get a meter GUI create a LevelMeterSource in your AudioProcessor 49 | or whatever instance processes an AudioBuffer. 50 | Then call LevelMeterSource::measureBlock (AudioBuffer& buf) to 51 | create the readings. 52 | */ 53 | class LevelMeterSource 54 | { 55 | private: 56 | class ChannelData 57 | { 58 | public: 59 | ChannelData (const size_t rmsWindow = 8) : 60 | max (), 61 | maxOverall (), 62 | clip (false), 63 | reduction (1.0f), 64 | hold (0), 65 | rmsHistory ((size_t) rmsWindow, 0.0), 66 | rmsSum (0.0), 67 | rmsPtr (0) 68 | {} 69 | 70 | ChannelData (const ChannelData& other) : 71 | max (other.max.load() ), 72 | maxOverall(other.maxOverall.load() ), 73 | clip (other.clip.load() ), 74 | reduction (other.reduction.load()), 75 | hold (other.hold.load()), 76 | rmsHistory (8, 0.0), 77 | rmsSum (0.0), 78 | rmsPtr (0) 79 | {} 80 | 81 | ChannelData& operator=(const ChannelData& other) 82 | { 83 | max.store (other.max.load()); 84 | maxOverall.store (other.maxOverall.load()); 85 | clip.store (other.clip.load()); 86 | reduction.store (other.reduction.load()); 87 | hold.store (other.hold.load()); 88 | rmsHistory.resize (other.rmsHistory.size(), 0.0); 89 | rmsSum = 0.0; 90 | rmsPtr = 0; 91 | return (*this); 92 | } 93 | 94 | std::atomic max; 95 | std::atomic maxOverall; 96 | std::atomic clip; 97 | std::atomic reduction; 98 | 99 | float getAvgRMS () const 100 | { 101 | if (rmsHistory.size() > 0) 102 | return std::sqrt(std::accumulate (rmsHistory.begin(), rmsHistory.end(), 0.0f) / static_cast(rmsHistory.size())); 103 | 104 | return float (std::sqrt (rmsSum)); 105 | } 106 | 107 | void setLevels (const juce::int64 time, const float newMax, const float newRms, const juce::int64 newHoldMSecs) 108 | { 109 | if (newMax > 1.0 || newRms > 1.0) 110 | clip = true; 111 | 112 | maxOverall = fmaxf (maxOverall, newMax); 113 | if (newMax >= max) 114 | { 115 | max = std::min (1.0f, newMax); 116 | hold = time + newHoldMSecs; 117 | } 118 | else if (time > hold) 119 | { 120 | max = std::min (1.0f, newMax); 121 | } 122 | pushNextRMS (std::min (1.0f, newRms)); 123 | } 124 | 125 | void setRMSsize (const size_t numBlocks) 126 | { 127 | rmsHistory.assign (numBlocks, 0.0); 128 | rmsSum = 0.0; 129 | if (numBlocks > 1) 130 | rmsPtr %= rmsHistory.size(); 131 | else 132 | rmsPtr = 0; 133 | } 134 | private: 135 | void pushNextRMS (const float newRMS) 136 | { 137 | const double squaredRMS = std::min (newRMS * newRMS, 1.0f); 138 | if (rmsHistory.size() > 0) 139 | { 140 | rmsHistory [(size_t) rmsPtr] = squaredRMS; 141 | rmsPtr = (rmsPtr + 1) % rmsHistory.size(); 142 | } 143 | else 144 | { 145 | rmsSum = squaredRMS; 146 | } 147 | } 148 | 149 | std::atomic hold; 150 | std::vector rmsHistory; 151 | std::atomic rmsSum; 152 | size_t rmsPtr; 153 | }; 154 | 155 | public: 156 | LevelMeterSource () : 157 | holdMSecs (500), 158 | lastMeasurement (0), 159 | suspended (false) 160 | {} 161 | 162 | ~LevelMeterSource () 163 | { 164 | masterReference.clear(); 165 | } 166 | 167 | /** 168 | Resize the meters data containers. Set the 169 | \param numChannels to the number of channels. If you don't do this in prepareToPlay, 170 | it will be done when calling measureBlock, but a few bytes will be allocated 171 | on the audio thread, so be aware. 172 | \param rmsWindow is the number of rms values to gather. Keep that aligned with 173 | the sampleRate and the blocksize to get reproducable results. 174 | e.g. `rmsWindow = msecs * 0.001f * sampleRate / blockSize;` 175 | */ 176 | void resize (const int channels, const int rmsWindow) 177 | { 178 | levels.resize (size_t (channels), ChannelData (size_t (rmsWindow))); 179 | for (ChannelData& l : levels) 180 | l.setRMSsize (size_t (rmsWindow)); 181 | 182 | newDataFlag = true; 183 | } 184 | 185 | /** 186 | Call this method to measure a block af levels to be displayed in the meters 187 | */ 188 | template 189 | void measureBlock (const juce::AudioBuffer& buffer) 190 | { 191 | lastMeasurement = juce::Time::currentTimeMillis(); 192 | if (! suspended) 193 | { 194 | const int numChannels = buffer.getNumChannels (); 195 | const int numSamples = buffer.getNumSamples (); 196 | 197 | for (int channel=0; channel < std::min (numChannels, int (levels.size())); ++channel) { 198 | levels [size_t (channel)].setLevels (lastMeasurement, 199 | buffer.getMagnitude (channel, 0, numSamples), 200 | buffer.getRMSLevel (channel, 0, numSamples), 201 | holdMSecs); 202 | } 203 | } 204 | 205 | newDataFlag = true; 206 | } 207 | 208 | /** 209 | This is called from the GUI. If processing was stalled, this will pump zeroes into the buffer, 210 | until the readings return to zero. 211 | */ 212 | void decayIfNeeded() 213 | { 214 | juce::int64 time = juce::Time::currentTimeMillis(); 215 | if (time - lastMeasurement < 100) 216 | return; 217 | 218 | lastMeasurement = time; 219 | for (size_t channel=0; channel < levels.size(); ++channel) 220 | { 221 | levels [channel].setLevels (lastMeasurement, 0.0f, 0.0f, holdMSecs); 222 | levels [channel].reduction = 1.0f; 223 | } 224 | 225 | newDataFlag = true; 226 | } 227 | 228 | /** 229 | With the reduction level you can add an extra bar do indicate, by what amount the level was reduced. 230 | This will be printed on top of the bar with half the width. 231 | @param channel the channel index, that was reduced 232 | @param reduction the factor for the reduction applied to the channel, 1.0=no reduction, 0.0=block completely 233 | */ 234 | void setReductionLevel (const int channel, const float reduction) 235 | { 236 | if (juce::isPositiveAndBelow (channel, static_cast (levels.size ()))) 237 | levels [size_t (channel)].reduction = reduction; 238 | } 239 | 240 | /** 241 | With the reduction level you can add an extra bar do indicate, by what amount the level was reduced. 242 | This will be printed on top of the bar with half the width. 243 | @param reduction the factor for the reduction applied to all channels, 1.0=no reduction, 0.0=muted completely 244 | */ 245 | void setReductionLevel (const float reduction) 246 | { 247 | for (auto& channel : levels) 248 | channel.reduction = reduction; 249 | } 250 | 251 | /** 252 | Set the timeout, how long the peak line will be displayed, before it resets to the 253 | current peak 254 | */ 255 | void setMaxHoldMS (const juce::int64 millis) 256 | { 257 | holdMSecs = millis; 258 | } 259 | 260 | /** 261 | Returns the reduction level. This value is not computed but can be set 262 | manually via \see setReductionLevel. 263 | */ 264 | float getReductionLevel (const int channel) const 265 | { 266 | if (juce::isPositiveAndBelow (channel, static_cast (levels.size ()))) 267 | return levels [size_t (channel)].reduction; 268 | 269 | return -1.0f; 270 | } 271 | 272 | /** 273 | This is the max level as displayed by the little line above the RMS bar. 274 | It is reset by \see setMaxHoldMS. 275 | */ 276 | float getMaxLevel (const int channel) const 277 | { 278 | return levels.at (size_t (channel)).max; 279 | } 280 | 281 | /** 282 | This is the max level as displayed under the bar as number. 283 | It will stay up until \see clearMaxNum was called. 284 | */ 285 | float getMaxOverallLevel (const int channel) const 286 | { 287 | return levels.at (size_t (channel)).maxOverall; 288 | } 289 | 290 | /** 291 | This is the RMS level that the bar will indicate. It is 292 | summed over rmsWindow number of blocks/measureBlock calls. 293 | */ 294 | float getRMSLevel (const int channel) const 295 | { 296 | return levels.at (size_t (channel)).getAvgRMS(); 297 | } 298 | 299 | /** 300 | Returns the status of the clip flag. 301 | */ 302 | bool getClipFlag (const int channel) const 303 | { 304 | return levels.at (size_t (channel)).clip; 305 | } 306 | 307 | /** 308 | Reset the clip flag to reset the indicator in the meter 309 | */ 310 | void clearClipFlag (const int channel) 311 | { 312 | levels.at (size_t (channel)).clip = false; 313 | } 314 | 315 | void clearAllClipFlags () 316 | { 317 | for (ChannelData& l : levels) { 318 | l.clip = false; 319 | } 320 | } 321 | 322 | /** 323 | Reset the max number to minus infinity 324 | */ 325 | void clearMaxNum (const int channel) 326 | { 327 | levels.at (size_t (channel)).maxOverall = infinity; 328 | } 329 | 330 | /** 331 | Reset all max numbers 332 | */ 333 | void clearAllMaxNums () 334 | { 335 | for (ChannelData& l : levels) { 336 | l.maxOverall = infinity; 337 | } 338 | } 339 | 340 | /** 341 | Get the number of channels to be displayed 342 | */ 343 | int getNumChannels () const 344 | { 345 | return static_cast (levels.size()); 346 | } 347 | 348 | /** 349 | The measure can be suspended, e.g. to save CPU when no meter is displayed. 350 | In this case, the \see measureBlock will return immediately 351 | */ 352 | void setSuspended (const bool shouldBeSuspended) 353 | { 354 | suspended = shouldBeSuspended; 355 | } 356 | 357 | bool checkNewDataFlag() const 358 | { 359 | return newDataFlag; 360 | } 361 | 362 | void resetNewDataFlag() 363 | { 364 | newDataFlag = false; 365 | } 366 | 367 | private: 368 | JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (LevelMeterSource) 369 | juce::WeakReference::Master masterReference; 370 | friend class juce::WeakReference; 371 | 372 | constexpr static float infinity = -100.0f; 373 | 374 | std::vector levels; 375 | 376 | juce::int64 holdMSecs; 377 | 378 | std::atomic lastMeasurement; 379 | 380 | bool newDataFlag = true; 381 | 382 | bool suspended; 383 | }; 384 | 385 | /*@}*/ 386 | 387 | } // end namespace foleys 388 | -------------------------------------------------------------------------------- /LevelMeter/LevelMeter.h: -------------------------------------------------------------------------------- 1 | /* 2 | ============================================================================== 3 | Copyright (c) 2017 - 2020 Foleys Finest Audio Ltd. - Daniel Walz 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without modification, 7 | are permitted provided that the following conditions are met: 8 | 1. Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 2. Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 3. Neither the name of the copyright holder nor the names of its contributors 14 | may be used to endorse or promote products derived from this software without 15 | specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 18 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 | IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 21 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 22 | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 24 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 25 | OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 26 | OF THE POSSIBILITY OF SUCH DAMAGE. 27 | ============================================================================== 28 | 29 | LevelMeter.h 30 | Created: 5 Apr 2016 9:49:54am 31 | Author: Daniel Walz 32 | 33 | ============================================================================== 34 | */ 35 | 36 | #pragma once 37 | 38 | namespace foleys 39 | { 40 | 41 | /** @addtogroup ff_meters */ 42 | /*@{*/ 43 | 44 | class LevelMeterLookAndFeel; 45 | 46 | //============================================================================== 47 | /* 48 | \class LevelMeter 49 | \brief A component to display live gain and RMS readings 50 | 51 | This class is used to display a level reading. It supports max and RMS levels. 52 | You can also set a reduction value to display, the definition of that value is up to you. 53 | */ 54 | class LevelMeter : public juce::Component, private juce::Timer 55 | { 56 | public: 57 | 58 | enum MeterFlags 59 | { 60 | Default = 0x0000, /**< Default is showing all channels in the LevelMeterSource without a border */ 61 | Horizontal = 0x0001, /**< Displays the level bars horizontally */ 62 | Vintage = 0x0002, /**< Switches to a special mode of old school meters (to come) */ 63 | SingleChannel = 0x0004, /**< Display only one channel meter. \see setSelectedChannel */ 64 | HasBorder = 0x0008, /**< Displays a rounded border around the meter. This is used with the default constructor */ 65 | Reduction = 0x0010, /**< This turns the bar into a reduction bar. 66 | The additional reduction bar is automatically added, as soon a reduction value < 1.0 is set 67 | in the LevelMeterSource. \see LevelMeterSource::setReductionLevel */ 68 | Minimal = 0x0020, /**< For a stereo meter, this tries to save space by showing only one line tickmarks in the middle and no max numbers */ 69 | MaxNumber = 0x0040 /**< To add level meter to Minimal, set this flag */ 70 | }; 71 | 72 | enum ColourIds 73 | { 74 | lmTextColour = 0x2200001, /**< Colour for the numbers etc. */ 75 | lmTextDeactiveColour, /**< Unused, will eventually be removed */ 76 | lmTextClipColour, /**< Colour to print the max number if it has clipped */ 77 | lmTicksColour, /**< Colour for the tick marks */ 78 | lmOutlineColour, /**< Colour for the frame around all */ 79 | lmBackgroundColour, /**< Background colour */ 80 | lmBackgroundClipColour, /**< This is the colour of the clip indicator if it has clipped */ 81 | lmMeterForegroundColour, /**< Unused, will eventually be removed */ 82 | lmMeterOutlineColour, /**< Colour for the outlines of meter bars etc. */ 83 | lmMeterBackgroundColour, /**< Background colour for the actual meter bar and the max number */ 84 | lmMeterMaxNormalColour, /**< Text colour for the max number, if under warn threshold */ 85 | lmMeterMaxWarnColour, /**< Text colour for the max number, if between warn threshold and clip threshold */ 86 | lmMeterMaxOverColour, /**< Text colour for the max number, if above the clip threshold */ 87 | lmMeterGradientLowColour, /**< Colour for the meter bar under the warn threshold */ 88 | lmMeterGradientMidColour, /**< Colour for the meter bar in the warn area */ 89 | lmMeterGradientMaxColour, /**< Colour for the meter bar at the clip threshold */ 90 | lmMeterReductionColour /**< Colour for the reduction meter displayed within the meter */ 91 | }; 92 | 93 | /** 94 | These methods define a interface for the LookAndFeel class of juce. 95 | The LevelMeter needs a LookAndFeel, that implements these methods. 96 | There is a default implementation to be included in your custom LookAndFeel class, \see LookAndFeelMethods.h 97 | */ 98 | class LookAndFeelMethods { 99 | public: 100 | virtual ~LookAndFeelMethods() {} 101 | 102 | /** Define your default colours in this callback */ 103 | virtual void setupDefaultMeterColours () = 0; 104 | 105 | /** Call this to create the cached ColourGradients after changing colours of the meter gradients */ 106 | virtual void updateMeterGradients () = 0; 107 | 108 | /** Override this to change the inner rectangle in case you want to paint a border e.g. */ 109 | virtual juce::Rectangle getMeterInnerBounds (juce::Rectangle bounds, 110 | MeterFlags meterType) const = 0; 111 | 112 | /** Override this callback to define the placement of a meter channel. */ 113 | virtual juce::Rectangle getMeterBounds (juce::Rectangle bounds, 114 | MeterFlags meterType, 115 | int numChannels, 116 | int channel) const = 0; 117 | 118 | /** Override this callback to define the placement of the actual meter bar. */ 119 | virtual juce::Rectangle getMeterBarBounds (juce::Rectangle bounds, 120 | MeterFlags meterType) const = 0; 121 | 122 | /** Override this callback to define the placement of the tickmarks. 123 | To disable this feature return an empty rectangle. */ 124 | virtual juce::Rectangle getMeterTickmarksBounds (juce::Rectangle bounds, 125 | MeterFlags meterType) const = 0; 126 | 127 | /** Override this callback to define the placement of the clip indicator light. 128 | To disable this feature return an empty rectangle. */ 129 | virtual juce::Rectangle getMeterClipIndicatorBounds (juce::Rectangle bounds, 130 | MeterFlags meterType) const = 0; 131 | 132 | 133 | /** Override this to draw background and if wanted a frame. If the frame takes space away, 134 | it should return the reduced bounds */ 135 | virtual juce::Rectangle drawBackground (juce::Graphics&, 136 | MeterFlags meterType, 137 | juce::Rectangle bounds) = 0; 138 | 139 | /** This is called to draw the actual numbers and bars on top of the static background */ 140 | virtual void drawMeterBars (juce::Graphics&, 141 | MeterFlags meterType, 142 | juce::Rectangle bounds, 143 | const LevelMeterSource* source, 144 | int fixedNumChannels=-1, 145 | int selectedChannel=-1) = 0; 146 | 147 | /** This draws the static background of the whole level meter group with all channels */ 148 | virtual void drawMeterBarsBackground (juce::Graphics&, 149 | MeterFlags meterType, 150 | juce::Rectangle bounds, 151 | int numChannels, 152 | int fixedNumChannels=-1) = 0; 153 | 154 | /** This draws a group of informations representing one channel */ 155 | virtual void drawMeterChannel (juce::Graphics&, 156 | MeterFlags meterType, 157 | juce::Rectangle bounds, 158 | const LevelMeterSource* source, 159 | int selectedChannel) = 0; 160 | 161 | /** This draws the static backgrounds representing one channel */ 162 | virtual void drawMeterChannelBackground (juce::Graphics&, 163 | MeterFlags meterType, 164 | juce::Rectangle bounds) = 0; 165 | 166 | /** This callback draws the actual level bar. The background has an extra callback */ 167 | virtual void drawMeterBar (juce::Graphics&, 168 | MeterFlags meterType, 169 | juce::Rectangle bounds, 170 | float rms, const float peak) = 0; 171 | 172 | /** This callback draws an reduction from top. Only triggered, if a reduction < 1.0 is set in the LevelMeterSource */ 173 | virtual void drawMeterReduction (juce::Graphics& g, 174 | foleys::LevelMeter::MeterFlags meterType, 175 | juce::Rectangle bounds, 176 | float reduction) = 0; 177 | 178 | /** This draws the background for the actual level bar */ 179 | virtual void drawMeterBarBackground (juce::Graphics&, 180 | MeterFlags meterType, 181 | juce::Rectangle bounds) = 0; 182 | 183 | /** This draws the tickmarks for the level scale. It is painted on the static background */ 184 | virtual void drawTickMarks (juce::Graphics&, 185 | MeterFlags meterType, 186 | juce::Rectangle bounds) = 0; 187 | 188 | /** This callback draws the clip indicator. The background has an extra callback */ 189 | virtual void drawClipIndicator (juce::Graphics&, 190 | MeterFlags meterType, 191 | juce::Rectangle bounds, 192 | bool hasClipped) = 0; 193 | 194 | /** This draws the background for the clip indicator LED */ 195 | virtual void drawClipIndicatorBackground (juce::Graphics&, 196 | MeterFlags meterType, 197 | juce::Rectangle bounds) = 0; 198 | 199 | /** Override this callback to define the placement of the max level. 200 | To disable this feature return an empty rectangle. */ 201 | virtual juce::Rectangle getMeterMaxNumberBounds (juce::Rectangle bounds, 202 | MeterFlags meterType) const = 0; 203 | 204 | /** This callback draws the number of maximum level. The background has an extra callback */ 205 | virtual void drawMaxNumber (juce::Graphics&, 206 | MeterFlags meterType, 207 | juce::Rectangle bounds, 208 | float maxGain) = 0; 209 | 210 | /** This draws the background for the maximum level display */ 211 | virtual void drawMaxNumberBackground (juce::Graphics&, 212 | MeterFlags meterType, 213 | juce::Rectangle bounds) = 0; 214 | 215 | /** This is called by the frontend to check, if the clip indicator was clicked (e.g. for reset) */ 216 | virtual int hitTestClipIndicator (juce::Point position, 217 | MeterFlags meterType, 218 | juce::Rectangle bounds, 219 | const LevelMeterSource* source) const = 0; 220 | 221 | /** This is called by the frontend to check, if the maximum level number was clicked (e.g. for reset) */ 222 | virtual int hitTestMaxNumber (juce::Point position, 223 | MeterFlags meterType, 224 | juce::Rectangle bounds, 225 | const LevelMeterSource* source) const = 0; 226 | }; 227 | 228 | LevelMeter (MeterFlags type = HasBorder); 229 | ~LevelMeter () override; 230 | 231 | /** 232 | Allows to change the meter's configuration by setting a combination of MeterFlags 233 | */ 234 | void setMeterFlags (MeterFlags type); 235 | 236 | void paint (juce::Graphics&) override; 237 | 238 | void resized () override; 239 | 240 | void visibilityChanged () override; 241 | 242 | void timerCallback () override; 243 | 244 | /** 245 | Set a LevelMeterSource to display. This separation is used, so the source can work in the processing and the 246 | GUI can display the values. 247 | */ 248 | void setMeterSource (foleys::LevelMeterSource* source); 249 | 250 | /** 251 | Set a specific channel to display. This is only useful, if MeterFlags::SingleChannel is set. 252 | */ 253 | void setSelectedChannel (int c); 254 | 255 | /** 256 | If you don't know, how many channels will be in the processblock, you can set this number to avoid stretching 257 | the width of the channels. 258 | */ 259 | void setFixedNumChannels (int numChannels); 260 | 261 | void setRefreshRateHz (int newRefreshRate); 262 | 263 | /** 264 | Unset the clip indicator flag for a channel. Use -1 to reset all clip indicators. 265 | */ 266 | void clearClipIndicator (int channel=-1); 267 | 268 | /** 269 | Set the max level display back to -inf for a channel. Use -1 to reset all max levels. 270 | */ 271 | void clearMaxLevelDisplay (int channel=-1); 272 | 273 | /** 274 | This lambda is called when the user clicks on a clip light. It is initially set to clear all clip lights 275 | and max level numbers. 276 | */ 277 | std::function onClipLightClicked; 278 | 279 | /** 280 | This lambda is called when the user clicks on a max level display. It is initially set to clear all clip lights 281 | and max level numbers. 282 | */ 283 | std::function onMaxLevelClicked; 284 | 285 | /** 286 | \internal 287 | */ 288 | void mouseDown (const juce::MouseEvent& event) override; 289 | 290 | void parentHierarchyChanged() override; 291 | void lookAndFeelChanged() override; 292 | 293 | /** 294 | DEPRECATED: Instead of using the Listener, use the new lambdas: 295 | \see onMaxLevelClicked, onClipLightClicked 296 | 297 | This Listener interface is meant to implement behaviour if either the clip indicator or the max level text 298 | is clicked. 299 | 300 | An example implementation could look like this (+alt means clear all, else clear the clicked number): 301 | \code{.cpp} 302 | void clipLightClicked (LevelMeter* clickedMeter, const int channel, ModifierKeys mods) override 303 | { 304 | clickedMeter->clearClipIndicator (mods.isAltDown() ? -1 : channel); 305 | } 306 | 307 | void maxLevelClicked (LevelMeter* clickedMeter, const int channel, ModifierKeys mods) override 308 | { 309 | clickedMeter->clearMaxLevelDisplay (mods.isAltDown() ? -1 : channel); 310 | } 311 | \endcode 312 | */ 313 | class Listener 314 | { 315 | public: 316 | virtual ~Listener() = default; 317 | /** 318 | This is called, when the user clicks a clip indicator. It can be used to reset the clip indicator. 319 | To allow different behaviour, e.g. resetting only one indicator or even all meters spread over the UI. 320 | \see clearClipIndicator, maxLevelClicked 321 | */ 322 | virtual void clipLightClicked (foleys::LevelMeter* meter, int channel, juce::ModifierKeys mods) = 0; 323 | /** 324 | This is called, when the user clicks a max level text. It can be used to reset the max number. 325 | \see clearMaxLevelDisplay, clipLightClicked 326 | */ 327 | virtual void maxLevelClicked (foleys::LevelMeter* meter, int channel, juce::ModifierKeys mods) = 0; 328 | }; 329 | 330 | void addListener (foleys::LevelMeter::Listener*); 331 | 332 | void removeListener (foleys::LevelMeter::Listener*); 333 | 334 | private: 335 | JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (LevelMeter) 336 | 337 | juce::WeakReference source; 338 | 339 | int selectedChannel = -1; 340 | int fixedNumChannels = -1; 341 | MeterFlags meterType = HasBorder; 342 | int refreshRate = 30; 343 | bool useBackgroundImage = false; 344 | juce::Image backgroundImage; 345 | bool backgroundNeedsRepaint = true; 346 | 347 | std::unique_ptr fallbackLookAndFeel; 348 | LevelMeter::LookAndFeelMethods* lmLookAndFeel = nullptr; 349 | 350 | juce::ListenerList listeners; 351 | }; 352 | 353 | inline LevelMeter::MeterFlags operator|(LevelMeter::MeterFlags a, LevelMeter::MeterFlags b) 354 | {return static_cast(static_cast(a) | static_cast(b));} 355 | 356 | /*@}*/ 357 | 358 | } // end namespace foleys 359 | -------------------------------------------------------------------------------- /LookAndFeel/LevelMeterLookAndFeelMethods.h: -------------------------------------------------------------------------------- 1 | /* 2 | ============================================================================== 3 | Copyright (c) 2017 - 2020 Foleys Finest Audio Ltd. - Daniel Walz 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without modification, 7 | are permitted provided that the following conditions are met: 8 | 1. Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 2. Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 3. Neither the name of the copyright holder nor the names of its contributors 14 | may be used to endorse or promote products derived from this software without 15 | specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 18 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 | IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 21 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 22 | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 24 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 25 | OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 26 | OF THE POSSIBILITY OF SUCH DAMAGE. 27 | 28 | ============================================================================== 29 | 30 | \file LevelMeterLookAndFeelMethods.h 31 | Author: Daniel Walz 32 | 33 | To use the default implementation of your LevelMeter in your LookAndFeel, 34 | inherit your LookAndFeel class from LevelMeter::LookAndFeelMethods and 35 | include this file inside your class declaration in a public section. 36 | 37 | In the Constructor you might want to call setupDefaultMeterColours() to 38 | setup the default colour scheme. 39 | ============================================================================== 40 | */ 41 | 42 | 43 | // include this file inside the implementation of your LookAndFeel to get the default implementation instead of copying it there 44 | 45 | void setupDefaultMeterColours () override 46 | { 47 | setColour (foleys::LevelMeter::lmTextColour, juce::Colours::lightgrey); 48 | setColour (foleys::LevelMeter::lmTextClipColour, juce::Colours::white); 49 | setColour (foleys::LevelMeter::lmTextDeactiveColour, juce::Colours::darkgrey); 50 | setColour (foleys::LevelMeter::lmTicksColour, juce::Colours::orange); 51 | setColour (foleys::LevelMeter::lmOutlineColour, juce::Colours::orange); 52 | setColour (foleys::LevelMeter::lmBackgroundColour, juce::Colour (0xff050a29)); 53 | setColour (foleys::LevelMeter::lmBackgroundClipColour, juce::Colours::red); 54 | setColour (foleys::LevelMeter::lmMeterForegroundColour, juce::Colours::green); 55 | setColour (foleys::LevelMeter::lmMeterOutlineColour, juce::Colours::lightgrey); 56 | setColour (foleys::LevelMeter::lmMeterBackgroundColour, juce::Colours::darkgrey); 57 | setColour (foleys::LevelMeter::lmMeterMaxNormalColour, juce::Colours::lightgrey); 58 | setColour (foleys::LevelMeter::lmMeterMaxWarnColour, juce::Colours::orange); 59 | setColour (foleys::LevelMeter::lmMeterMaxOverColour, juce::Colours::darkred); 60 | setColour (foleys::LevelMeter::lmMeterGradientLowColour, juce::Colours::green); 61 | setColour (foleys::LevelMeter::lmMeterGradientMidColour, juce::Colours::lightgoldenrodyellow); 62 | setColour (foleys::LevelMeter::lmMeterGradientMaxColour, juce::Colours::red); 63 | setColour (foleys::LevelMeter::lmMeterReductionColour, juce::Colours::orange); 64 | } 65 | 66 | void updateMeterGradients () override 67 | { 68 | horizontalGradient.clearColours(); 69 | verticalGradient.clearColours(); 70 | } 71 | 72 | juce::Rectangle getMeterInnerBounds (juce::Rectangle bounds, 73 | foleys::LevelMeter::MeterFlags meterType) const override 74 | { 75 | if (meterType & foleys::LevelMeter::HasBorder) 76 | { 77 | const auto corner = std::min (bounds.getWidth(), bounds.getHeight()) * 0.01f; 78 | return bounds.reduced (3 + corner); 79 | } 80 | 81 | return bounds; 82 | } 83 | 84 | juce::Rectangle getMeterBounds (juce::Rectangle bounds, 85 | foleys::LevelMeter::MeterFlags meterType, 86 | int numChannels, 87 | int channel) const override 88 | { 89 | if (meterType & foleys::LevelMeter::SingleChannel) { 90 | return bounds; 91 | } 92 | else { 93 | if (meterType & foleys::LevelMeter::Horizontal) { 94 | const float h = bounds.getHeight() / numChannels; 95 | return bounds.withHeight (h).withY (bounds.getY() + channel * h); 96 | } 97 | else { 98 | const float w = bounds.getWidth() / numChannels; 99 | return bounds.withWidth (w).withX (bounds.getX() + channel * w); 100 | } 101 | } 102 | return juce::Rectangle (); 103 | } 104 | 105 | /** Override this callback to define the placement of the actual meter bar. */ 106 | juce::Rectangle getMeterBarBounds (juce::Rectangle bounds, 107 | foleys::LevelMeter::MeterFlags meterType) const override 108 | { 109 | if (meterType & foleys::LevelMeter::Minimal) 110 | { 111 | if (meterType & foleys::LevelMeter::Horizontal) 112 | { 113 | const auto margin = bounds.getHeight() * 0.05f; 114 | const auto h = bounds.getHeight() - 2.0f * margin; 115 | const auto left = bounds.getX() + margin; 116 | const auto right = bounds.getRight() - (4.0f * margin + h); 117 | return juce::Rectangle(bounds.getX() + margin, 118 | bounds.getY() + margin, 119 | right - left, 120 | h); 121 | } 122 | 123 | const auto margin = bounds.getWidth() * 0.05f; 124 | const auto top = bounds.getY() + 2.0f * margin + bounds.getWidth() * 0.5f; 125 | const auto bottom = (meterType & foleys::LevelMeter::MaxNumber) ? 126 | bounds.getBottom() - (3.0f * margin + (bounds.getWidth() - margin * 2.0f)) 127 | : bounds.getBottom() - margin; 128 | return juce::Rectangle(bounds.getX() + margin, top, 129 | bounds.getWidth() - margin * 2.0f, bottom - top); 130 | } 131 | 132 | if (meterType & foleys::LevelMeter::Vintage) 133 | return bounds; 134 | 135 | if (meterType & foleys::LevelMeter::Horizontal) 136 | { 137 | const auto margin = bounds.getHeight() * 0.05f; 138 | const auto h = bounds.getHeight() * 0.5f - 2.0f * margin; 139 | const auto left = 60.0f + 3.0f * margin; 140 | const auto right = bounds.getRight() - (4.0f * margin + h * 0.5f); 141 | return juce::Rectangle(bounds.getX() + left, 142 | bounds.getY() + margin, 143 | right - left, 144 | h); 145 | } 146 | 147 | const auto margin = bounds.getWidth() * 0.05f; 148 | const auto w = bounds.getWidth() * 0.45f; 149 | const auto top = bounds.getY() + 2.0f * margin + w * 0.5f; 150 | const auto bottom = bounds.getBottom() - (2.0f * margin + 25.0f); 151 | return juce::Rectangle(bounds.getX() + margin, top, w, bottom - top); 152 | } 153 | 154 | /** Override this callback to define the placement of the tickmarks. 155 | To disable this feature return an empty rectangle. */ 156 | juce::Rectangle getMeterTickmarksBounds (juce::Rectangle bounds, 157 | foleys::LevelMeter::MeterFlags meterType) const override 158 | { 159 | if (meterType & foleys::LevelMeter::Minimal) 160 | { 161 | if (meterType & foleys::LevelMeter::Horizontal) { 162 | return getMeterBarBounds(bounds, meterType).reduced (0.0, 2.0); 163 | } 164 | else { 165 | return getMeterBarBounds(bounds, meterType).reduced (2.0, 0.0); 166 | } 167 | } 168 | 169 | if (meterType & foleys::LevelMeter::Vintage) 170 | return bounds; 171 | 172 | if (meterType & foleys::LevelMeter::Horizontal) { 173 | const auto margin = bounds.getHeight() * 0.05f; 174 | const auto h = bounds.getHeight() * 0.5f - 2.0f * margin; 175 | const auto left = 60.0f + 3.0f * margin; 176 | const auto right = bounds.getRight() - (4.0f * margin + h * 0.5f); 177 | return juce::Rectangle(bounds.getX() + left, 178 | bounds.getCentreY() + margin, 179 | right - left, 180 | h); 181 | } 182 | else 183 | { 184 | const auto margin = bounds.getWidth() * 0.05f; 185 | const auto w = bounds.getWidth() * 0.45f; 186 | const auto top = bounds.getY() + 2.0f * margin + w * 0.5f + 2.0f; 187 | const auto bottom = bounds.getBottom() - (2.0f * margin + 25.0f + 2.0f); 188 | return juce::Rectangle(bounds.getCentreX(), top, w, bottom - top); 189 | } 190 | 191 | return juce::Rectangle (); 192 | } 193 | 194 | /** Override this callback to define the placement of the clip indicator light. 195 | To disable this feature return an empty rectangle. */ 196 | juce::Rectangle getMeterClipIndicatorBounds (juce::Rectangle bounds, 197 | foleys::LevelMeter::MeterFlags meterType) const override 198 | { 199 | if (meterType & foleys::LevelMeter::Minimal) 200 | { 201 | if (meterType & foleys::LevelMeter::Horizontal) 202 | { 203 | const auto margin = bounds.getHeight() * 0.05f; 204 | const auto h = bounds.getHeight() - 2.0f * margin; 205 | return juce::Rectangle(bounds.getRight() - (margin + h), 206 | bounds.getY() + margin, 207 | h, 208 | h); 209 | } 210 | else 211 | { 212 | const auto margin = bounds.getWidth() * 0.05f; 213 | const auto w = bounds.getWidth() - margin * 2.0f; 214 | return juce::Rectangle(bounds.getX() + margin, 215 | bounds.getY() + margin, 216 | w, 217 | w * 0.5f); 218 | } 219 | } 220 | else if (meterType & foleys::LevelMeter::Vintage) 221 | { 222 | return bounds; 223 | } 224 | else 225 | { 226 | if (meterType & foleys::LevelMeter::Horizontal) 227 | { 228 | const auto margin = bounds.getHeight() * 0.05f; 229 | const auto h = bounds.getHeight() * 0.5f - 2.0f * margin; 230 | return juce::Rectangle(bounds.getRight() - (margin + h * 0.5f), 231 | bounds.getY() + margin, 232 | h * 0.5f, 233 | h); 234 | } 235 | else 236 | { 237 | const auto margin = bounds.getWidth() * 0.05f; 238 | const auto w = bounds.getWidth() * 0.45f; 239 | return juce::Rectangle(bounds.getX() + margin, 240 | bounds.getY() + margin, 241 | w, 242 | w * 0.5f); 243 | } 244 | } 245 | return juce::Rectangle (); 246 | } 247 | 248 | /** Override this callback to define the placement of the max level. 249 | To disable this feature return an empty rectangle. */ 250 | juce::Rectangle getMeterMaxNumberBounds (juce::Rectangle bounds, 251 | foleys::LevelMeter::MeterFlags meterType) const override 252 | { 253 | if (meterType & foleys::LevelMeter::Minimal) 254 | { 255 | if (meterType & foleys::LevelMeter::MaxNumber) 256 | { 257 | if (meterType & foleys::LevelMeter::Horizontal) 258 | { 259 | const auto margin = bounds.getHeight() * 0.05f; 260 | const auto h = bounds.getHeight() - 2.0f * margin; 261 | return juce::Rectangle(bounds.getRight() - (margin + h), 262 | bounds.getY() + margin, 263 | h, h); 264 | } 265 | else 266 | { 267 | const auto margin = bounds.getWidth() * 0.05f; 268 | const auto w = bounds.getWidth() - margin * 2.0f; 269 | const auto h = w * 0.6f; 270 | return juce::Rectangle(bounds.getX() + margin, 271 | bounds.getBottom() - (margin + h), 272 | w, h); 273 | } 274 | } 275 | else 276 | { 277 | return juce::Rectangle (); 278 | } 279 | } 280 | else if (meterType & foleys::LevelMeter::Vintage) { 281 | return bounds; 282 | } 283 | else { 284 | if (meterType & foleys::LevelMeter::Horizontal) 285 | { 286 | const auto margin = bounds.getHeight() * 0.05f; 287 | return juce::Rectangle(bounds.getX() + margin, 288 | bounds.getCentreY() + margin, 289 | 60, 290 | bounds.getHeight() * 0.5f - margin * 2.0f); 291 | } 292 | else 293 | { 294 | const auto margin = bounds.getWidth() * 0.05f; 295 | return juce::Rectangle(bounds.getX() + margin, 296 | bounds.getBottom() - (margin + 25), 297 | bounds.getWidth() - 2 * margin, 298 | 25.0); 299 | } 300 | } 301 | } 302 | 303 | juce::Rectangle drawBackground (juce::Graphics& g, 304 | foleys::LevelMeter::MeterFlags meterType, 305 | juce::Rectangle bounds) override 306 | { 307 | g.setColour (findColour (foleys::LevelMeter::lmBackgroundColour)); 308 | if (meterType & foleys::LevelMeter::HasBorder) 309 | { 310 | const auto corner = std::min (bounds.getWidth(), bounds.getHeight()) * 0.01f; 311 | g.fillRoundedRectangle (bounds, corner); 312 | g.setColour (findColour (foleys::LevelMeter::lmOutlineColour)); 313 | g.drawRoundedRectangle (bounds.reduced (3), corner, 2); 314 | return bounds.reduced (3 + corner); 315 | } 316 | else 317 | { 318 | g.fillRect (bounds); 319 | return bounds; 320 | } 321 | } 322 | 323 | void drawMeterBars (juce::Graphics& g, 324 | foleys::LevelMeter::MeterFlags meterType, 325 | juce::Rectangle bounds, 326 | const foleys::LevelMeterSource* source, 327 | int fixedNumChannels=-1, 328 | int selectedChannel=-1) override 329 | { 330 | if (source == nullptr) 331 | return; 332 | 333 | const juce::Rectangle innerBounds = getMeterInnerBounds (bounds, meterType); 334 | const int numChannels = source->getNumChannels(); 335 | if (meterType & foleys::LevelMeter::Minimal) 336 | { 337 | if (meterType & foleys::LevelMeter::Horizontal) 338 | { 339 | const float height = innerBounds.getHeight() / (2 * numChannels - 1); 340 | juce::Rectangle meter = innerBounds.withHeight (height); 341 | for (int channel=0; channel < numChannels; ++channel) 342 | { 343 | meter.setY (height * channel * 2); 344 | { 345 | juce::Rectangle meterBarBounds = getMeterBarBounds (meter, meterType); 346 | drawMeterBar (g, meterType, meterBarBounds, 347 | source->getRMSLevel (channel), 348 | source->getMaxLevel (channel)); 349 | const float reduction = source->getReductionLevel (channel); 350 | if (reduction < 1.0) 351 | drawMeterReduction (g, meterType, 352 | meterBarBounds.withBottom (meterBarBounds.getCentreY()), 353 | reduction); 354 | } 355 | 356 | juce::Rectangle clip = getMeterClipIndicatorBounds (meter, meterType); 357 | if (! clip.isEmpty()) 358 | drawClipIndicator (g, meterType, clip, source->getClipFlag (channel)); 359 | juce::Rectangle maxNum = getMeterMaxNumberBounds (meter, meterType); 360 | 361 | if (! maxNum.isEmpty()) 362 | drawMaxNumber(g, meterType, maxNum, source->getMaxOverallLevel (channel)); 363 | 364 | if (channel < numChannels-1) 365 | { 366 | meter.setY (height * (channel * 2 + 1)); 367 | juce::Rectangle ticks = getMeterTickmarksBounds (meter, meterType); 368 | if (! ticks.isEmpty()) 369 | drawTickMarks (g, meterType, ticks); 370 | } 371 | } 372 | } 373 | else 374 | { 375 | const float width = innerBounds.getWidth() / (2 * numChannels - 1); 376 | juce::Rectangle meter = innerBounds.withWidth(width); 377 | for (int channel=0; channel < numChannels; ++channel) { 378 | meter.setX (width * channel * 2); 379 | { 380 | juce::Rectangle meterBarBounds = getMeterBarBounds (meter, meterType); 381 | drawMeterBar (g, meterType, getMeterBarBounds (meter, meterType), 382 | source->getRMSLevel (channel), 383 | source->getMaxLevel (channel)); 384 | const float reduction = source->getReductionLevel (channel); 385 | if (reduction < 1.0) 386 | drawMeterReduction (g, meterType, 387 | meterBarBounds.withLeft (meterBarBounds.getCentreX()), 388 | reduction); 389 | } 390 | juce::Rectangle clip = getMeterClipIndicatorBounds (meter, meterType); 391 | if (! clip.isEmpty()) 392 | drawClipIndicator (g, meterType, clip, source->getClipFlag (channel)); 393 | juce::Rectangle maxNum = getMeterMaxNumberBounds (innerBounds.withWidth (innerBounds.getWidth() / numChannels).withX (innerBounds.getX() + channel * (innerBounds.getWidth() / numChannels)), meterType); 394 | if (! maxNum.isEmpty()) 395 | drawMaxNumber(g, meterType, maxNum, source->getMaxOverallLevel (channel)); 396 | if (channel < numChannels-1) { 397 | meter.setX (width * (channel * 2 + 1)); 398 | juce::Rectangle ticks = getMeterTickmarksBounds (meter, meterType); 399 | if (! ticks.isEmpty()) 400 | drawTickMarks (g, meterType, ticks); 401 | } 402 | } 403 | } 404 | } 405 | else if (meterType & foleys::LevelMeter::SingleChannel) 406 | { 407 | if (selectedChannel >= 0) 408 | drawMeterChannel (g, meterType, innerBounds, source, selectedChannel); 409 | } 410 | else 411 | { 412 | const int numDrawnChannels = fixedNumChannels < 0 ? numChannels : fixedNumChannels; 413 | for (int channel=0; channel < numChannels; ++channel) 414 | drawMeterChannel (g, meterType, 415 | getMeterBounds (innerBounds, meterType, numDrawnChannels, channel), 416 | source, channel); 417 | } 418 | } 419 | 420 | void drawMeterBarsBackground (juce::Graphics& g, 421 | foleys::LevelMeter::MeterFlags meterType, 422 | juce::Rectangle bounds, 423 | int numChannels, 424 | int fixedNumChannels) override 425 | { 426 | const juce::Rectangle innerBounds = getMeterInnerBounds (bounds, meterType); 427 | if (meterType & foleys::LevelMeter::Minimal) { 428 | if (meterType & foleys::LevelMeter::Horizontal) { 429 | const float height = innerBounds.getHeight() / (2 * numChannels - 1); 430 | juce::Rectangle meter = innerBounds.withHeight (height); 431 | for (int channel=0; channel < numChannels; ++channel) { 432 | meter.setY (height * channel * 2); 433 | drawMeterBarBackground (g, meterType, getMeterBarBounds (meter, meterType)); 434 | juce::Rectangle clip = getMeterClipIndicatorBounds (meter, meterType); 435 | if (! clip.isEmpty()) 436 | drawClipIndicatorBackground (g, meterType, clip); 437 | if (channel < numChannels-1) { 438 | meter.setY (height * (channel * 2 + 1)); 439 | juce::Rectangle ticks = getMeterTickmarksBounds (meter, meterType); 440 | if (! ticks.isEmpty()) 441 | drawTickMarks (g, meterType, ticks); 442 | } 443 | } 444 | } 445 | else { 446 | const float width = innerBounds.getWidth() / (2 * numChannels - 1); 447 | juce::Rectangle meter = innerBounds.withWidth(width); 448 | for (int channel=0; channel < numChannels; ++channel) { 449 | meter.setX (width * channel * 2); 450 | drawMeterBarBackground (g, meterType, getMeterBarBounds (meter, meterType)); 451 | juce::Rectangle clip = getMeterClipIndicatorBounds (meter, meterType); 452 | if (! clip.isEmpty()) 453 | drawClipIndicatorBackground (g, meterType, clip); 454 | if (channel < numChannels-1) { 455 | meter.setX (width * (channel * 2 + 1)); 456 | juce::Rectangle ticks = getMeterTickmarksBounds (meter, meterType); 457 | if (! ticks.isEmpty()) 458 | drawTickMarks (g, meterType, ticks); 459 | } 460 | } 461 | } 462 | } 463 | else if (meterType & foleys::LevelMeter::SingleChannel) { 464 | drawMeterChannelBackground (g, meterType, innerBounds); 465 | } 466 | else { 467 | for (int channel=0; channel < numChannels; ++channel) { 468 | drawMeterChannelBackground (g, meterType, 469 | getMeterBounds (innerBounds, meterType, 470 | fixedNumChannels < 0 ? numChannels : fixedNumChannels, 471 | channel)); 472 | } 473 | } 474 | } 475 | 476 | 477 | void drawMeterChannel (juce::Graphics& g, 478 | foleys::LevelMeter::MeterFlags meterType, 479 | juce::Rectangle bounds, 480 | const foleys::LevelMeterSource* source, 481 | int selectedChannel) override 482 | { 483 | if (source == nullptr) 484 | return; 485 | 486 | juce::Rectangle meter = getMeterBarBounds (bounds, meterType); 487 | if (! meter.isEmpty()) 488 | { 489 | if (meterType & foleys::LevelMeter::Reduction) 490 | { 491 | drawMeterBar (g, meterType, meter, 492 | source->getReductionLevel (selectedChannel), 493 | 0.0f); 494 | } 495 | else 496 | { 497 | drawMeterBar (g, meterType, meter, 498 | source->getRMSLevel (selectedChannel), 499 | source->getMaxLevel (selectedChannel)); 500 | const float reduction = source->getReductionLevel (selectedChannel); 501 | if (reduction < 1.0) 502 | { 503 | if (meterType & foleys::LevelMeter::Horizontal) 504 | drawMeterReduction (g, meterType, 505 | meter.withBottom (meter.getCentreY()), 506 | reduction); 507 | else 508 | drawMeterReduction (g, meterType, 509 | meter.withLeft (meter.getCentreX()), 510 | reduction); 511 | } 512 | } 513 | } 514 | 515 | if (source->getClipFlag (selectedChannel)) { 516 | juce::Rectangle clip = getMeterClipIndicatorBounds (bounds, meterType); 517 | if (! clip.isEmpty()) 518 | drawClipIndicator (g, meterType, clip, true); 519 | } 520 | 521 | juce::Rectangle maxes = getMeterMaxNumberBounds (bounds, meterType); 522 | if (! maxes.isEmpty()) 523 | { 524 | if (meterType & foleys::LevelMeter::Reduction) 525 | drawMaxNumber (g, meterType, maxes, source->getReductionLevel (selectedChannel)); 526 | else 527 | drawMaxNumber (g, meterType, maxes, source->getMaxOverallLevel(selectedChannel)); 528 | } 529 | } 530 | 531 | void drawMeterChannelBackground (juce::Graphics& g, 532 | foleys::LevelMeter::MeterFlags meterType, 533 | juce::Rectangle bounds) override 534 | { 535 | juce::Rectangle meter = getMeterBarBounds (bounds, meterType); 536 | if (! meter.isEmpty()) 537 | drawMeterBarBackground (g, meterType, meter); 538 | 539 | juce::Rectangle clip = getMeterClipIndicatorBounds (bounds, meterType); 540 | if (! clip.isEmpty()) 541 | drawClipIndicatorBackground (g, meterType, clip); 542 | 543 | juce::Rectangle ticks = getMeterTickmarksBounds (bounds, meterType); 544 | if (! ticks.isEmpty()) 545 | drawTickMarks (g, meterType, ticks); 546 | 547 | juce::Rectangle maxes = getMeterMaxNumberBounds (bounds, meterType); 548 | if (! maxes.isEmpty()) { 549 | drawMaxNumberBackground (g, meterType, maxes); 550 | } 551 | } 552 | 553 | void drawMeterBar (juce::Graphics& g, 554 | foleys::LevelMeter::MeterFlags meterType, 555 | juce::Rectangle bounds, 556 | float rms, float peak) override 557 | { 558 | const auto infinity = meterType & foleys::LevelMeter::Reduction ? -30.0f : -100.0f; 559 | const auto rmsDb = juce::Decibels::gainToDecibels (rms, infinity); 560 | const auto peakDb = juce::Decibels::gainToDecibels (peak, infinity); 561 | 562 | const juce::Rectangle floored (ceilf (bounds.getX()) + 1.0f, ceilf (bounds.getY()) + 1.0f, 563 | floorf (bounds.getRight()) - (ceilf (bounds.getX() + 2.0f)), 564 | floorf (bounds.getBottom()) - (ceilf (bounds.getY()) + 2.0f)); 565 | 566 | if (meterType & foleys::LevelMeter::Vintage) { 567 | // TODO 568 | } 569 | else if (meterType & foleys::LevelMeter::Reduction) 570 | { 571 | const float limitDb = juce::Decibels::gainToDecibels (rms, infinity); 572 | g.setColour (findColour (foleys::LevelMeter::lmMeterReductionColour)); 573 | if (meterType & foleys::LevelMeter::Horizontal) 574 | g.fillRect (floored.withLeft (floored.getX() + limitDb * floored.getWidth() / infinity)); 575 | else 576 | g.fillRect (floored.withBottom (floored.getY() + limitDb * floored.getHeight() / infinity)); 577 | } 578 | else 579 | { 580 | if (meterType & foleys::LevelMeter::Horizontal) 581 | { 582 | if (horizontalGradient.getNumColours() < 2) 583 | { 584 | horizontalGradient = juce::ColourGradient (findColour (foleys::LevelMeter::lmMeterGradientLowColour), 585 | floored.getX(), floored.getY(), 586 | findColour (foleys::LevelMeter::lmMeterGradientMaxColour), 587 | floored.getRight(), floored.getY(), false); 588 | horizontalGradient.addColour (0.5, findColour (foleys::LevelMeter::lmMeterGradientLowColour)); 589 | horizontalGradient.addColour (0.75, findColour (foleys::LevelMeter::lmMeterGradientMidColour)); 590 | } 591 | g.setGradientFill (horizontalGradient); 592 | g.fillRect (floored.withRight (floored.getRight() - rmsDb * floored.getWidth() / infinity)); 593 | 594 | if (peakDb > -49.0) 595 | { 596 | g.setColour (findColour ((peakDb > -0.3f) ? foleys::LevelMeter::lmMeterMaxOverColour : 597 | ((peakDb > -5.0) ? foleys::LevelMeter::lmMeterMaxWarnColour : 598 | foleys::LevelMeter::lmMeterMaxNormalColour))); 599 | g.drawVerticalLine (juce::roundToInt (floored.getRight() - juce::jmax (peakDb * floored.getWidth() / infinity, 0.0f)), 600 | floored.getY(), floored.getBottom()); 601 | } 602 | } 603 | else 604 | { 605 | // vertical 606 | if (verticalGradient.getNumColours() < 2) 607 | { 608 | verticalGradient = juce::ColourGradient (findColour (foleys::LevelMeter::lmMeterGradientLowColour), 609 | floored.getX(), floored.getBottom(), 610 | findColour (foleys::LevelMeter::lmMeterGradientMaxColour), 611 | floored.getX(), floored.getY(), false); 612 | verticalGradient.addColour (0.5f, findColour (foleys::LevelMeter::lmMeterGradientLowColour)); 613 | verticalGradient.addColour (0.75f, findColour (foleys::LevelMeter::lmMeterGradientMidColour)); 614 | } 615 | g.setGradientFill (verticalGradient); 616 | g.fillRect (floored.withTop (floored.getY() + rmsDb * floored.getHeight() / infinity)); 617 | 618 | if (peakDb > -49.0f) { 619 | g.setColour (findColour ((peakDb > -0.3f) ? foleys::LevelMeter::lmMeterMaxOverColour : 620 | ((peakDb > -5.0f) ? foleys::LevelMeter::lmMeterMaxWarnColour : 621 | foleys::LevelMeter::lmMeterMaxNormalColour))); 622 | g.drawHorizontalLine (juce::roundToInt (floored.getY() + juce::jmax (peakDb * floored.getHeight() / infinity, 0.0f)), 623 | floored.getX(), floored.getRight()); 624 | } 625 | } 626 | } 627 | } 628 | 629 | void drawMeterReduction (juce::Graphics& g, 630 | foleys::LevelMeter::MeterFlags meterType, 631 | juce::Rectangle bounds, 632 | float reduction) override 633 | { 634 | const auto infinity = -30.0f; 635 | 636 | const juce::Rectangle floored (ceilf (bounds.getX()) + 1.0f, ceilf (bounds.getY()) + 1.0f, 637 | floorf (bounds.getRight()) - (ceilf (bounds.getX() + 2.0f)), 638 | floorf (bounds.getBottom()) - (ceilf (bounds.getY()) + 2.0f)); 639 | 640 | const auto limitDb = juce::Decibels::gainToDecibels (reduction, infinity); 641 | g.setColour (findColour (foleys::LevelMeter::lmMeterReductionColour)); 642 | if (meterType & foleys::LevelMeter::Horizontal) { 643 | g.fillRect (floored.withLeft (floored.getX() + limitDb * floored.getWidth() / infinity)); 644 | } 645 | else { 646 | g.fillRect (floored.withBottom (floored.getY() + limitDb * floored.getHeight() / infinity)); 647 | } 648 | } 649 | 650 | void drawMeterBarBackground (juce::Graphics& g, 651 | foleys::LevelMeter::MeterFlags meterType, 652 | juce::Rectangle bounds) override 653 | { 654 | juce::ignoreUnused (meterType); 655 | g.setColour (findColour (foleys::LevelMeter::lmMeterBackgroundColour)); 656 | g.fillRect (bounds); 657 | 658 | g.setColour (findColour (foleys::LevelMeter::lmMeterOutlineColour)); 659 | g.drawRect (bounds, 1.0); 660 | } 661 | 662 | void drawTickMarks (juce::Graphics& g, 663 | foleys::LevelMeter::MeterFlags meterType, 664 | juce::Rectangle bounds) override 665 | { 666 | const auto infinity = meterType & foleys::LevelMeter::Reduction ? -30.0f : -100.0f; 667 | 668 | g.setColour (findColour (foleys::LevelMeter::lmTicksColour)); 669 | if (meterType & foleys::LevelMeter::Minimal) 670 | { 671 | if (meterType & foleys::LevelMeter::Horizontal) 672 | { 673 | for (int i=0; i<11; ++i) 674 | g.drawVerticalLine (juce::roundToInt (bounds.getX() + i * 0.1f * bounds.getWidth()), 675 | bounds.getY() + 4, 676 | bounds.getBottom() - 4); 677 | } 678 | else 679 | { 680 | const auto h = (bounds.getHeight() - 2.0f) * 0.1f; 681 | for (int i=0; i<11; ++i) 682 | { 683 | g.drawHorizontalLine (juce::roundToInt (bounds.getY() + i * h + 1), 684 | bounds.getX() + 4, 685 | bounds.getRight()); 686 | } 687 | if (h > 10 && bounds.getWidth() > 20) 688 | { 689 | // don't print tiny numbers 690 | g.setFont (h * 0.5f); 691 | for (int i=0; i<10; ++i) { 692 | g.drawFittedText (juce::String (i * 0.1 * infinity), 693 | juce::roundToInt (bounds.getX()), 694 | juce::roundToInt (bounds.getY() + i * h + 2), 695 | juce::roundToInt (bounds.getWidth()), 696 | juce::roundToInt (h * 0.6f), 697 | juce::Justification::centredTop, 1); 698 | } 699 | } 700 | } 701 | } 702 | else if (meterType & foleys::LevelMeter::Vintage) 703 | { 704 | // TODO 705 | } 706 | else 707 | { 708 | if (meterType & foleys::LevelMeter::Horizontal) 709 | { 710 | for (int i=0; i<11; ++i) 711 | g.drawVerticalLine (juce::roundToInt (bounds.getX() + i * 0.1f * bounds.getWidth()), 712 | bounds.getY() + 4, 713 | bounds.getBottom() - 4); 714 | } 715 | else 716 | { 717 | const auto h = (bounds.getHeight() - 2.0f) * 0.05f; 718 | g.setFont (h * 0.8f); 719 | for (int i=0; i<21; ++i) { 720 | const auto y = bounds.getY() + i * h; 721 | if (i % 2 == 0) 722 | { 723 | g.drawHorizontalLine (juce::roundToInt (y + 1), 724 | bounds.getX() + 4, 725 | bounds.getRight()); 726 | if (i < 20) 727 | { 728 | g.drawFittedText (juce::String (i * 0.05 * infinity), 729 | juce::roundToInt (bounds.getX()), 730 | juce::roundToInt (y + 4), 731 | juce::roundToInt (bounds.getWidth()), 732 | juce::roundToInt (h * 0.6f), 733 | juce::Justification::topRight, 1); 734 | } 735 | } 736 | else 737 | { 738 | g.drawHorizontalLine (juce::roundToInt (y + 2), 739 | bounds.getX() + 4, 740 | bounds.getCentreX()); 741 | } 742 | } 743 | } 744 | } 745 | } 746 | 747 | void drawClipIndicator (juce::Graphics& g, 748 | foleys::LevelMeter::MeterFlags meterType, 749 | juce::Rectangle bounds, 750 | bool hasClipped) override 751 | { 752 | juce::ignoreUnused (meterType); 753 | 754 | g.setColour (findColour (hasClipped ? foleys::LevelMeter::lmBackgroundClipColour : foleys::LevelMeter::lmMeterBackgroundColour)); 755 | g.fillRect (bounds); 756 | g.setColour (findColour (foleys::LevelMeter::lmMeterOutlineColour)); 757 | g.drawRect (bounds, 1.0); 758 | } 759 | 760 | void drawClipIndicatorBackground (juce::Graphics& g, 761 | foleys::LevelMeter::MeterFlags meterType, 762 | juce::Rectangle bounds) override 763 | { 764 | juce::ignoreUnused (meterType); 765 | 766 | g.setColour (findColour (foleys::LevelMeter::lmMeterBackgroundColour)); 767 | g.fillRect (bounds); 768 | g.setColour (findColour (foleys::LevelMeter::lmMeterOutlineColour)); 769 | g.drawRect (bounds, 1.0); 770 | } 771 | 772 | void drawMaxNumber (juce::Graphics& g, 773 | foleys::LevelMeter::MeterFlags meterType, 774 | juce::Rectangle bounds, 775 | float maxGain) override 776 | { 777 | juce::ignoreUnused (meterType); 778 | 779 | g.setColour (findColour (foleys::LevelMeter::lmMeterBackgroundColour)); 780 | g.fillRect (bounds); 781 | const float maxDb = juce::Decibels::gainToDecibels (maxGain, -100.0f); 782 | g.setColour (findColour (maxDb > 0.0 ? foleys::LevelMeter::lmTextClipColour : foleys::LevelMeter::lmTextColour)); 783 | g.setFont (bounds.getHeight() * 0.5f); 784 | g.drawFittedText (juce::String (maxDb, 1) + " dB", 785 | bounds.reduced (2.0).toNearestInt(), 786 | juce::Justification::centred, 1); 787 | g.setColour (findColour (foleys::LevelMeter::lmMeterOutlineColour)); 788 | g.drawRect (bounds, 1.0); 789 | } 790 | 791 | void drawMaxNumberBackground (juce::Graphics& g, 792 | foleys::LevelMeter::MeterFlags meterType, 793 | juce::Rectangle bounds) override 794 | { 795 | juce::ignoreUnused (meterType); 796 | 797 | g.setColour (findColour (foleys::LevelMeter::lmMeterBackgroundColour)); 798 | g.fillRect (bounds); 799 | } 800 | 801 | int hitTestClipIndicator (juce::Point position, 802 | foleys::LevelMeter::MeterFlags meterType, 803 | juce::Rectangle bounds, 804 | const foleys::LevelMeterSource* source) const override 805 | { 806 | if (source) { 807 | const int numChannels = source->getNumChannels(); 808 | for (int i=0; i < numChannels; ++i) { 809 | if (getMeterClipIndicatorBounds (getMeterBounds 810 | (bounds, meterType, source->getNumChannels(), i), meterType) 811 | .contains (position.toFloat())) { 812 | return i; 813 | } 814 | } 815 | } 816 | return -1; 817 | } 818 | 819 | int hitTestMaxNumber (juce::Point position, 820 | foleys::LevelMeter::MeterFlags meterType, 821 | juce::Rectangle bounds, 822 | const foleys::LevelMeterSource* source) const override 823 | { 824 | if (source) { 825 | const int numChannels = source->getNumChannels(); 826 | for (int i=0; i < numChannels; ++i) { 827 | if (getMeterMaxNumberBounds (getMeterBounds 828 | (bounds, meterType, source->getNumChannels(), i), meterType) 829 | .contains (position.toFloat())) { 830 | return i; 831 | } 832 | } 833 | } 834 | return -1; 835 | } 836 | 837 | private: 838 | 839 | juce::ColourGradient horizontalGradient; 840 | juce::ColourGradient verticalGradient; 841 | 842 | 843 | -------------------------------------------------------------------------------- /Doxyfile: -------------------------------------------------------------------------------- 1 | # Doxyfile 1.8.1 2 | 3 | # This file describes the settings to be used by the documentation system 4 | # doxygen (www.doxygen.org) for a project 5 | # 6 | # All text after a hash (#) is considered a comment and will be ignored 7 | # The format is: 8 | # TAG = value [value, ...] 9 | # For lists items can also be appended using: 10 | # TAG += value [value, ...] 11 | # Values that contain spaces should be placed between quotes (" ") 12 | 13 | #--------------------------------------------------------------------------- 14 | # Project related configuration options 15 | #--------------------------------------------------------------------------- 16 | 17 | # This tag specifies the encoding used for all characters in the config file 18 | # that follow. The default is UTF-8 which is also the encoding used for all 19 | # text before the first occurrence of this tag. Doxygen uses libiconv (or the 20 | # iconv built into libc) for the transcoding. See 21 | # http://www.gnu.org/software/libiconv for the list of possible encodings. 22 | 23 | DOXYFILE_ENCODING = UTF-8 24 | 25 | # The PROJECT_NAME tag is a single word (or sequence of words) that should 26 | # identify the project. Note that if you do not use Doxywizard you need 27 | # to put quotes around the project name if it contains spaces. 28 | 29 | PROJECT_NAME = ff_meters 30 | 31 | # The PROJECT_NUMBER tag can be used to enter a project or revision number. 32 | # This could be handy for archiving the generated documentation or 33 | # if some version control system is used. 34 | 35 | PROJECT_NUMBER = 36 | 37 | # Using the PROJECT_BRIEF tag one can provide an optional one line description 38 | # for a project that appears at the top of each page and should give viewer 39 | # a quick idea about the purpose of the project. Keep the description short. 40 | 41 | PROJECT_BRIEF = "Add meter components to visualise AudioBuffers" 42 | 43 | # With the PROJECT_LOGO tag one can specify an logo or icon that is 44 | # included in the documentation. The maximum height of the logo should not 45 | # exceed 55 pixels and the maximum width should not exceed 200 pixels. 46 | # Doxygen will copy the logo to the output directory. 47 | 48 | PROJECT_LOGO = 49 | 50 | # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) 51 | # base path where the generated documentation will be put. 52 | # If a relative path is entered, it will be relative to the location 53 | # where doxygen was started. If left blank the current directory will be used. 54 | 55 | OUTPUT_DIRECTORY = 56 | 57 | # If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 58 | # 4096 sub-directories (in 2 levels) under the output directory of each output 59 | # format and will distribute the generated files over these directories. 60 | # Enabling this option can be useful when feeding doxygen a huge amount of 61 | # source files, where putting all generated files in the same directory would 62 | # otherwise cause performance problems for the file system. 63 | 64 | CREATE_SUBDIRS = NO 65 | 66 | # The OUTPUT_LANGUAGE tag is used to specify the language in which all 67 | # documentation generated by doxygen is written. Doxygen will use this 68 | # information to generate all constant output in the proper language. 69 | # The default language is English, other supported languages are: 70 | # Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, 71 | # Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, 72 | # Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English 73 | # messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, 74 | # Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, 75 | # Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. 76 | 77 | OUTPUT_LANGUAGE = English 78 | 79 | # If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will 80 | # include brief member descriptions after the members that are listed in 81 | # the file and class documentation (similar to JavaDoc). 82 | # Set to NO to disable this. 83 | 84 | BRIEF_MEMBER_DESC = YES 85 | 86 | # If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend 87 | # the brief description of a member or function before the detailed description. 88 | # Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the 89 | # brief descriptions will be completely suppressed. 90 | 91 | REPEAT_BRIEF = YES 92 | 93 | # This tag implements a quasi-intelligent brief description abbreviator 94 | # that is used to form the text in various listings. Each string 95 | # in this list, if found as the leading text of the brief description, will be 96 | # stripped from the text and the result after processing the whole list, is 97 | # used as the annotated text. Otherwise, the brief description is used as-is. 98 | # If left blank, the following values are used ("$name" is automatically 99 | # replaced with the name of the entity): "The $name class" "The $name widget" 100 | # "The $name file" "is" "provides" "specifies" "contains" 101 | # "represents" "a" "an" "the" 102 | 103 | ABBREVIATE_BRIEF = 104 | 105 | # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then 106 | # Doxygen will generate a detailed section even if there is only a brief 107 | # description. 108 | 109 | ALWAYS_DETAILED_SEC = NO 110 | 111 | # If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all 112 | # inherited members of a class in the documentation of that class as if those 113 | # members were ordinary class members. Constructors, destructors and assignment 114 | # operators of the base classes will not be shown. 115 | 116 | INLINE_INHERITED_MEMB = NO 117 | 118 | # If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full 119 | # path before files name in the file list and in the header files. If set 120 | # to NO the shortest path that makes the file name unique will be used. 121 | 122 | FULL_PATH_NAMES = NO 123 | 124 | # If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag 125 | # can be used to strip a user-defined part of the path. Stripping is 126 | # only done if one of the specified strings matches the left-hand part of 127 | # the path. The tag can be used to show relative paths in the file list. 128 | # If left blank the directory from which doxygen is run is used as the 129 | # path to strip. 130 | 131 | STRIP_FROM_PATH = 132 | 133 | # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of 134 | # the path mentioned in the documentation of a class, which tells 135 | # the reader which header file to include in order to use a class. 136 | # If left blank only the name of the header file containing the class 137 | # definition is used. Otherwise one should specify the include paths that 138 | # are normally passed to the compiler using the -I flag. 139 | 140 | STRIP_FROM_INC_PATH = 141 | 142 | # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter 143 | # (but less readable) file names. This can be useful if your file system 144 | # doesn't support long names like on DOS, Mac, or CD-ROM. 145 | 146 | SHORT_NAMES = NO 147 | 148 | # If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen 149 | # will interpret the first line (until the first dot) of a JavaDoc-style 150 | # comment as the brief description. If set to NO, the JavaDoc 151 | # comments will behave just like regular Qt-style comments 152 | # (thus requiring an explicit @brief command for a brief description.) 153 | 154 | JAVADOC_AUTOBRIEF = YES 155 | 156 | # If the QT_AUTOBRIEF tag is set to YES then Doxygen will 157 | # interpret the first line (until the first dot) of a Qt-style 158 | # comment as the brief description. If set to NO, the comments 159 | # will behave just like regular Qt-style comments (thus requiring 160 | # an explicit \brief command for a brief description.) 161 | 162 | QT_AUTOBRIEF = NO 163 | 164 | # The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen 165 | # treat a multi-line C++ special comment block (i.e. a block of //! or /// 166 | # comments) as a brief description. This used to be the default behaviour. 167 | # The new default is to treat a multi-line C++ comment block as a detailed 168 | # description. Set this tag to YES if you prefer the old behaviour instead. 169 | 170 | MULTILINE_CPP_IS_BRIEF = YES 171 | 172 | # If the INHERIT_DOCS tag is set to YES (the default) then an undocumented 173 | # member inherits the documentation from any documented member that it 174 | # re-implements. 175 | 176 | INHERIT_DOCS = YES 177 | 178 | # If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce 179 | # a new page for each member. If set to NO, the documentation of a member will 180 | # be part of the file/class/namespace that contains it. 181 | 182 | SEPARATE_MEMBER_PAGES = NO 183 | 184 | # The TAB_SIZE tag can be used to set the number of spaces in a tab. 185 | # Doxygen uses this value to replace tabs by spaces in code fragments. 186 | 187 | TAB_SIZE = 4 188 | 189 | # This tag can be used to specify a number of aliases that acts 190 | # as commands in the documentation. An alias has the form "name=value". 191 | # For example adding "sideeffect=\par Side Effects:\n" will allow you to 192 | # put the command \sideeffect (or @sideeffect) in the documentation, which 193 | # will result in a user-defined paragraph with heading "Side Effects:". 194 | # You can put \n's in the value part of an alias to insert newlines. 195 | 196 | ALIASES = 197 | 198 | # This tag can be used to specify a number of word-keyword mappings (TCL only). 199 | # A mapping has the form "name=value". For example adding 200 | # "class=itcl::class" will allow you to use the command class in the 201 | # itcl::class meaning. 202 | 203 | TCL_SUBST = 204 | 205 | # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C 206 | # sources only. Doxygen will then generate output that is more tailored for C. 207 | # For instance, some of the names that are used will be different. The list 208 | # of all members will be omitted, etc. 209 | 210 | OPTIMIZE_OUTPUT_FOR_C = NO 211 | 212 | # Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java 213 | # sources only. Doxygen will then generate output that is more tailored for 214 | # Java. For instance, namespaces will be presented as packages, qualified 215 | # scopes will look different, etc. 216 | 217 | OPTIMIZE_OUTPUT_JAVA = NO 218 | 219 | # Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran 220 | # sources only. Doxygen will then generate output that is more tailored for 221 | # Fortran. 222 | 223 | OPTIMIZE_FOR_FORTRAN = NO 224 | 225 | # Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL 226 | # sources. Doxygen will then generate output that is tailored for 227 | # VHDL. 228 | 229 | OPTIMIZE_OUTPUT_VHDL = NO 230 | 231 | # Doxygen selects the parser to use depending on the extension of the files it 232 | # parses. With this tag you can assign which parser to use for a given extension. 233 | # Doxygen has a built-in mapping, but you can override or extend it using this 234 | # tag. The format is ext=language, where ext is a file extension, and language 235 | # is one of the parsers supported by doxygen: IDL, Java, Javascript, CSharp, C, 236 | # C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. For instance to make 237 | # doxygen treat .inc files as Fortran files (default is PHP), and .f files as C 238 | # (default is Fortran), use: inc=Fortran f=C. Note that for custom extensions 239 | # you also need to set FILE_PATTERNS otherwise the files are not read by doxygen. 240 | 241 | EXTENSION_MAPPING = 242 | 243 | # If MARKDOWN_SUPPORT is enabled (the default) then doxygen pre-processes all 244 | # comments according to the Markdown format, which allows for more readable 245 | # documentation. See http://daringfireball.net/projects/markdown/ for details. 246 | # The output of markdown processing is further processed by doxygen, so you 247 | # can mix doxygen, HTML, and XML commands with Markdown formatting. 248 | # Disable only in case of backward compatibilities issues. 249 | 250 | MARKDOWN_SUPPORT = YES 251 | 252 | # If you use STL classes (i.e. std::string, std::vector, etc.) but do not want 253 | # to include (a tag file for) the STL sources as input, then you should 254 | # set this tag to YES in order to let doxygen match functions declarations and 255 | # definitions whose arguments contain STL classes (e.g. func(std::string); v.s. 256 | # func(std::string) {}). This also makes the inheritance and collaboration 257 | # diagrams that involve STL classes more complete and accurate. 258 | 259 | BUILTIN_STL_SUPPORT = YES 260 | 261 | # If you use Microsoft's C++/CLI language, you should set this option to YES to 262 | # enable parsing support. 263 | 264 | CPP_CLI_SUPPORT = NO 265 | 266 | # Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. 267 | # Doxygen will parse them like normal C++ but will assume all classes use public 268 | # instead of private inheritance when no explicit protection keyword is present. 269 | 270 | SIP_SUPPORT = NO 271 | 272 | # For Microsoft's IDL there are propget and propput attributes to indicate getter 273 | # and setter methods for a property. Setting this option to YES (the default) 274 | # will make doxygen replace the get and set methods by a property in the 275 | # documentation. This will only work if the methods are indeed getting or 276 | # setting a simple type. If this is not the case, or you want to show the 277 | # methods anyway, you should set this option to NO. 278 | 279 | IDL_PROPERTY_SUPPORT = YES 280 | 281 | # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC 282 | # tag is set to YES, then doxygen will reuse the documentation of the first 283 | # member in the group (if any) for the other members of the group. By default 284 | # all members of a group must be documented explicitly. 285 | 286 | DISTRIBUTE_GROUP_DOC = NO 287 | 288 | # Set the SUBGROUPING tag to YES (the default) to allow class member groups of 289 | # the same type (for instance a group of public functions) to be put as a 290 | # subgroup of that type (e.g. under the Public Functions section). Set it to 291 | # NO to prevent subgrouping. Alternatively, this can be done per class using 292 | # the \nosubgrouping command. 293 | 294 | SUBGROUPING = YES 295 | 296 | # When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and 297 | # unions are shown inside the group in which they are included (e.g. using 298 | # @ingroup) instead of on a separate page (for HTML and Man pages) or 299 | # section (for LaTeX and RTF). 300 | 301 | INLINE_GROUPED_CLASSES = YES 302 | 303 | # When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and 304 | # unions with only public data fields will be shown inline in the documentation 305 | # of the scope in which they are defined (i.e. file, namespace, or group 306 | # documentation), provided this scope is documented. If set to NO (the default), 307 | # structs, classes, and unions are shown on a separate page (for HTML and Man 308 | # pages) or section (for LaTeX and RTF). 309 | 310 | INLINE_SIMPLE_STRUCTS = NO 311 | 312 | # When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum 313 | # is documented as struct, union, or enum with the name of the typedef. So 314 | # typedef struct TypeS {} TypeT, will appear in the documentation as a struct 315 | # with name TypeT. When disabled the typedef will appear as a member of a file, 316 | # namespace, or class. And the struct will be named TypeS. This can typically 317 | # be useful for C code in case the coding convention dictates that all compound 318 | # types are typedef'ed and only the typedef is referenced, never the tag name. 319 | 320 | TYPEDEF_HIDES_STRUCT = NO 321 | 322 | #--------------------------------------------------------------------------- 323 | # Build related configuration options 324 | #--------------------------------------------------------------------------- 325 | 326 | # If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in 327 | # documentation are documented, even if no documentation was available. 328 | # Private class members and static file members will be hidden unless 329 | # the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES 330 | 331 | EXTRACT_ALL = YES 332 | 333 | # If the EXTRACT_PRIVATE tag is set to YES all private members of a class 334 | # will be included in the documentation. 335 | 336 | EXTRACT_PRIVATE = NO 337 | 338 | # If the EXTRACT_PACKAGE tag is set to YES all members with package or internal 339 | # scope will be included in the documentation. 340 | 341 | EXTRACT_PACKAGE = NO 342 | 343 | # If the EXTRACT_STATIC tag is set to YES all static members of a file 344 | # will be included in the documentation. 345 | 346 | EXTRACT_STATIC = NO 347 | 348 | # If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) 349 | # defined locally in source files will be included in the documentation. 350 | # If set to NO only classes defined in header files are included. 351 | 352 | EXTRACT_LOCAL_CLASSES = Yes 353 | 354 | # This flag is only useful for Objective-C code. When set to YES local 355 | # methods, which are defined in the implementation section but not in 356 | # the interface are included in the documentation. 357 | # If set to NO (the default) only methods in the interface are included. 358 | 359 | EXTRACT_LOCAL_METHODS = NO 360 | 361 | # If this flag is set to YES, the members of anonymous namespaces will be 362 | # extracted and appear in the documentation as a namespace called 363 | # 'anonymous_namespace{file}', where file will be replaced with the base 364 | # name of the file that contains the anonymous namespace. By default 365 | # anonymous namespaces are hidden. 366 | 367 | EXTRACT_ANON_NSPACES = NO 368 | 369 | # If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all 370 | # undocumented members of documented classes, files or namespaces. 371 | # If set to NO (the default) these members will be included in the 372 | # various overviews, but no documentation section is generated. 373 | # This option has no effect if EXTRACT_ALL is enabled. 374 | 375 | HIDE_UNDOC_MEMBERS = NO 376 | 377 | # If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all 378 | # undocumented classes that are normally visible in the class hierarchy. 379 | # If set to NO (the default) these classes will be included in the various 380 | # overviews. This option has no effect if EXTRACT_ALL is enabled. 381 | 382 | HIDE_UNDOC_CLASSES = YES 383 | 384 | # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all 385 | # friend (class|struct|union) declarations. 386 | # If set to NO (the default) these declarations will be included in the 387 | # documentation. 388 | 389 | HIDE_FRIEND_COMPOUNDS = YES 390 | 391 | # If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any 392 | # documentation blocks found inside the body of a function. 393 | # If set to NO (the default) these blocks will be appended to the 394 | # function's detailed documentation block. 395 | 396 | HIDE_IN_BODY_DOCS = YES 397 | 398 | # The INTERNAL_DOCS tag determines if documentation 399 | # that is typed after a \internal command is included. If the tag is set 400 | # to NO (the default) then the documentation will be excluded. 401 | # Set it to YES to include the internal documentation. 402 | 403 | INTERNAL_DOCS = YES 404 | 405 | # If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate 406 | # file names in lower-case letters. If set to YES upper-case letters are also 407 | # allowed. This is useful if you have classes or files whose names only differ 408 | # in case and if your file system supports case sensitive file names. Windows 409 | # and Mac users are advised to set this option to NO. 410 | 411 | CASE_SENSE_NAMES = YES 412 | 413 | # If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen 414 | # will show members with their full class and namespace scopes in the 415 | # documentation. If set to YES the scope will be hidden. 416 | 417 | HIDE_SCOPE_NAMES = NO 418 | 419 | # If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen 420 | # will put a list of the files that are included by a file in the documentation 421 | # of that file. 422 | 423 | SHOW_INCLUDE_FILES = NO 424 | 425 | # If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen 426 | # will list include files with double quotes in the documentation 427 | # rather than with sharp brackets. 428 | 429 | FORCE_LOCAL_INCLUDES = NO 430 | 431 | # If the INLINE_INFO tag is set to YES (the default) then a tag [inline] 432 | # is inserted in the documentation for inline members. 433 | 434 | INLINE_INFO = NO 435 | 436 | # If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen 437 | # will sort the (detailed) documentation of file and class members 438 | # alphabetically by member name. If set to NO the members will appear in 439 | # declaration order. 440 | 441 | SORT_MEMBER_DOCS = NO 442 | 443 | # If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the 444 | # brief documentation of file, namespace and class members alphabetically 445 | # by member name. If set to NO (the default) the members will appear in 446 | # declaration order. 447 | 448 | SORT_BRIEF_DOCS = NO 449 | 450 | # If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen 451 | # will sort the (brief and detailed) documentation of class members so that 452 | # constructors and destructors are listed first. If set to NO (the default) 453 | # the constructors will appear in the respective orders defined by 454 | # SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. 455 | # This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO 456 | # and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. 457 | 458 | SORT_MEMBERS_CTORS_1ST = NO 459 | 460 | # If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the 461 | # hierarchy of group names into alphabetical order. If set to NO (the default) 462 | # the group names will appear in their defined order. 463 | 464 | SORT_GROUP_NAMES = NO 465 | 466 | # If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be 467 | # sorted by fully-qualified names, including namespaces. If set to 468 | # NO (the default), the class list will be sorted only by class name, 469 | # not including the namespace part. 470 | # Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. 471 | # Note: This option applies only to the class list, not to the 472 | # alphabetical list. 473 | 474 | SORT_BY_SCOPE_NAME = NO 475 | 476 | # If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to 477 | # do proper type resolution of all parameters of a function it will reject a 478 | # match between the prototype and the implementation of a member function even 479 | # if there is only one candidate or it is obvious which candidate to choose 480 | # by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen 481 | # will still accept a match between prototype and implementation in such cases. 482 | 483 | STRICT_PROTO_MATCHING = NO 484 | 485 | # The GENERATE_TODOLIST tag can be used to enable (YES) or 486 | # disable (NO) the todo list. This list is created by putting \todo 487 | # commands in the documentation. 488 | 489 | GENERATE_TODOLIST = NO 490 | 491 | # The GENERATE_TESTLIST tag can be used to enable (YES) or 492 | # disable (NO) the test list. This list is created by putting \test 493 | # commands in the documentation. 494 | 495 | GENERATE_TESTLIST = NO 496 | 497 | # The GENERATE_BUGLIST tag can be used to enable (YES) or 498 | # disable (NO) the bug list. This list is created by putting \bug 499 | # commands in the documentation. 500 | 501 | GENERATE_BUGLIST = NO 502 | 503 | # The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or 504 | # disable (NO) the deprecated list. This list is created by putting 505 | # \deprecated commands in the documentation. 506 | 507 | GENERATE_DEPRECATEDLIST= YES 508 | 509 | # The ENABLED_SECTIONS tag can be used to enable conditional 510 | # documentation sections, marked by \if sectionname ... \endif. 511 | 512 | ENABLED_SECTIONS = 513 | 514 | # The MAX_INITIALIZER_LINES tag determines the maximum number of lines 515 | # the initial value of a variable or macro consists of for it to appear in 516 | # the documentation. If the initializer consists of more lines than specified 517 | # here it will be hidden. Use a value of 0 to hide initializers completely. 518 | # The appearance of the initializer of individual variables and macros in the 519 | # documentation can be controlled using \showinitializer or \hideinitializer 520 | # command in the documentation regardless of this setting. 521 | 522 | MAX_INITIALIZER_LINES = 30 523 | 524 | # Set the SHOW_USED_FILES tag to NO to disable the list of files generated 525 | # at the bottom of the documentation of classes and structs. If set to YES the 526 | # list will mention the files that were used to generate the documentation. 527 | 528 | SHOW_USED_FILES = YES 529 | 530 | # Set the SHOW_FILES tag to NO to disable the generation of the Files page. 531 | # This will remove the Files entry from the Quick Index and from the 532 | # Folder Tree View (if specified). The default is YES. 533 | 534 | SHOW_FILES = YES 535 | 536 | # Set the SHOW_NAMESPACES tag to NO to disable the generation of the 537 | # Namespaces page. This will remove the Namespaces entry from the Quick Index 538 | # and from the Folder Tree View (if specified). The default is YES. 539 | 540 | SHOW_NAMESPACES = NO 541 | 542 | # The FILE_VERSION_FILTER tag can be used to specify a program or script that 543 | # doxygen should invoke to get the current version for each file (typically from 544 | # the version control system). Doxygen will invoke the program by executing (via 545 | # popen()) the command , where is the value of 546 | # the FILE_VERSION_FILTER tag, and is the name of an input file 547 | # provided by doxygen. Whatever the program writes to standard output 548 | # is used as the file version. See the manual for examples. 549 | 550 | FILE_VERSION_FILTER = 551 | 552 | # The LAYOUT_FILE tag can be used to specify a layout file which will be parsed 553 | # by doxygen. The layout file controls the global structure of the generated 554 | # output files in an output format independent way. The create the layout file 555 | # that represents doxygen's defaults, run doxygen with the -l option. 556 | # You can optionally specify a file name after the option, if omitted 557 | # DoxygenLayout.xml will be used as the name of the layout file. 558 | 559 | LAYOUT_FILE = 560 | 561 | # The CITE_BIB_FILES tag can be used to specify one or more bib files 562 | # containing the references data. This must be a list of .bib files. The 563 | # .bib extension is automatically appended if omitted. Using this command 564 | # requires the bibtex tool to be installed. See also 565 | # http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style 566 | # of the bibliography can be controlled using LATEX_BIB_STYLE. To use this 567 | # feature you need bibtex and perl available in the search path. 568 | 569 | CITE_BIB_FILES = 570 | 571 | #--------------------------------------------------------------------------- 572 | # configuration options related to warning and progress messages 573 | #--------------------------------------------------------------------------- 574 | 575 | # The QUIET tag can be used to turn on/off the messages that are generated 576 | # by doxygen. Possible values are YES and NO. If left blank NO is used. 577 | 578 | QUIET = NO 579 | 580 | # The WARNINGS tag can be used to turn on/off the warning messages that are 581 | # generated by doxygen. Possible values are YES and NO. If left blank 582 | # NO is used. 583 | 584 | WARNINGS = YES 585 | 586 | # If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings 587 | # for undocumented members. If EXTRACT_ALL is set to YES then this flag will 588 | # automatically be disabled. 589 | 590 | WARN_IF_UNDOCUMENTED = YES 591 | 592 | # If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for 593 | # potential errors in the documentation, such as not documenting some 594 | # parameters in a documented function, or documenting parameters that 595 | # don't exist or using markup commands wrongly. 596 | 597 | WARN_IF_DOC_ERROR = YES 598 | 599 | # The WARN_NO_PARAMDOC option can be enabled to get warnings for 600 | # functions that are documented, but have no documentation for their parameters 601 | # or return value. If set to NO (the default) doxygen will only warn about 602 | # wrong or incomplete parameter documentation, but not about the absence of 603 | # documentation. 604 | 605 | WARN_NO_PARAMDOC = NO 606 | 607 | # The WARN_FORMAT tag determines the format of the warning messages that 608 | # doxygen can produce. The string should contain the $file, $line, and $text 609 | # tags, which will be replaced by the file and line number from which the 610 | # warning originated and the warning text. Optionally the format may contain 611 | # $version, which will be replaced by the version of the file (if it could 612 | # be obtained via FILE_VERSION_FILTER) 613 | 614 | WARN_FORMAT = "$file:$line: $text" 615 | 616 | # The WARN_LOGFILE tag can be used to specify a file to which warning 617 | # and error messages should be written. If left blank the output is written 618 | # to stderr. 619 | 620 | WARN_LOGFILE = 621 | 622 | #--------------------------------------------------------------------------- 623 | # configuration options related to the input files 624 | #--------------------------------------------------------------------------- 625 | 626 | # The INPUT tag can be used to specify the files and/or directories that contain 627 | # documented source files. You may enter file names like "myfile.cpp" or 628 | # directories like "/usr/src/myproject". Separate the files or directories 629 | # with spaces. 630 | 631 | INPUT = . 632 | 633 | # This tag can be used to specify the character encoding of the source files 634 | # that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is 635 | # also the default input encoding. Doxygen uses libiconv (or the iconv built 636 | # into libc) for the transcoding. See http://www.gnu.org/software/libiconv for 637 | # the list of possible encodings. 638 | 639 | INPUT_ENCODING = UTF-8 640 | 641 | # If the value of the INPUT tag contains directories, you can use the 642 | # FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp 643 | # and *.h) to filter out the source-files in the directories. If left 644 | # blank the following patterns are tested: 645 | # *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh 646 | # *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py 647 | # *.f90 *.f *.for *.vhd *.vhdl 648 | 649 | FILE_PATTERNS = 650 | 651 | # The RECURSIVE tag can be used to turn specify whether or not subdirectories 652 | # should be searched for input files as well. Possible values are YES and NO. 653 | # If left blank NO is used. 654 | 655 | RECURSIVE = YES 656 | 657 | USE_MDFILE_AS_MAINPAGE = README.md 658 | 659 | # The EXCLUDE tag can be used to specify files and/or directories that should be 660 | # excluded from the INPUT source files. This way you can easily exclude a 661 | # subdirectory from a directory tree whose root is specified with the INPUT tag. 662 | # Note that relative paths are relative to the directory from which doxygen is 663 | # run. 664 | 665 | EXCLUDE = ../modules/juce_graphics/image_formats \ 666 | ../modules/juce_core/zip/zlib \ 667 | ../modules/juce_audio_formats/codecs/flac \ 668 | ../modules/juce_audio_formats/codecs/oggvorbis \ 669 | ../modules/juce_audio_basics/juce_audio_basics.h \ 670 | ../modules/juce_audio_basics/juce_audio_basics.cpp \ 671 | ../modules/juce_audio_devices/juce_audio_devices.h \ 672 | ../modules/juce_audio_devices/juce_audio_devices.cpp \ 673 | ../modules/juce_audio_devices/native \ 674 | ../modules/juce_audio_formats/juce_audio_formats.h \ 675 | ../modules/juce_audio_formats/juce_audio_formats.cpp \ 676 | ../modules/juce_audio_plugin_client/juce_audio_plugin_client.h \ 677 | ../modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses \ 678 | ../modules/juce_audio_processors/juce_audio_processors.h \ 679 | ../modules/juce_audio_processors/juce_audio_processors.cpp \ 680 | ../modules/juce_audio_utils/juce_audio_utils.h \ 681 | ../modules/juce_audio_utils/juce_audio_utils.cpp \ 682 | ../modules/juce_browser_plugin_client/juce_browser_plugin.h \ 683 | ../modules/juce_browser_plugin_client/juce_browser_plugin.cpp \ 684 | ../modules/juce_core/juce_core.h \ 685 | ../modules/juce_core/juce_core.cpp \ 686 | ../modules/juce_core/native \ 687 | ../modules/juce_cryptography/juce_cryptography.h \ 688 | ../modules/juce_cryptography/juce_cryptography.cpp \ 689 | ../modules/juce_data_structures/juce_data_structures.h \ 690 | ../modules/juce_data_structures/juce_data_structures.cpp \ 691 | ../modules/juce_events/juce_events.h \ 692 | ../modules/juce_events/juce_events.cpp \ 693 | ../modules/juce_events/native \ 694 | ../modules/juce_graphics/juce_graphics.h \ 695 | ../modules/juce_graphics/juce_graphics.cpp \ 696 | ../modules/juce_graphics/native \ 697 | ../modules/juce_gui_basics/juce_gui_basics.h \ 698 | ../modules/juce_gui_basics/juce_gui_basics.cpp \ 699 | ../modules/juce_gui_basics/native \ 700 | ../modules/juce_gui_extra/juce_gui_extra.h \ 701 | ../modules/juce_gui_extra/juce_gui_extra.cpp \ 702 | ../modules/juce_gui_extra/native \ 703 | ../modules/juce_opengl/juce_opengl.h \ 704 | ../modules/juce_opengl/juce_opengl.cpp \ 705 | ../modules/juce_opengl/native \ 706 | ../modules/juce_tracktion_marketplace/juce_tracktion_marketplace.h \ 707 | ../modules/juce_video/juce_video.h \ 708 | ../modules/juce_video/juce_video.cpp \ 709 | ../modules/juce_video/native 710 | 711 | # The EXCLUDE_SYMLINKS tag can be used to select whether or not files or 712 | # directories that are symbolic links (a Unix file system feature) are excluded 713 | # from the input. 714 | 715 | EXCLUDE_SYMLINKS = YES 716 | 717 | # If the value of the INPUT tag contains directories, you can use the 718 | # EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude 719 | # certain files from those directories. Note that the wildcards are matched 720 | # against the file with absolute path, so to exclude all test directories 721 | # for example use the pattern */test/* 722 | 723 | EXCLUDE_PATTERNS = juce_GIFLoader* \ 724 | juce_JPEGLoader* \ 725 | juce_PNGLoader* \ 726 | juce_FlacHeader.h 727 | 728 | # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names 729 | # (namespaces, classes, functions, etc.) that should be excluded from the 730 | # output. The symbol name can be a fully qualified name, a word, or if the 731 | # wildcard * is used, a substring. Examples: ANamespace, AClass, 732 | # AClass::ANamespace, ANamespace::*Test 733 | 734 | EXCLUDE_SYMBOLS = 735 | 736 | # The EXAMPLE_PATH tag can be used to specify one or more files or 737 | # directories that contain example code fragments that are included (see 738 | # the \include command). 739 | 740 | EXAMPLE_PATH = 741 | 742 | # If the value of the EXAMPLE_PATH tag contains directories, you can use the 743 | # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp 744 | # and *.h) to filter out the source-files in the directories. If left 745 | # blank all files are included. 746 | 747 | EXAMPLE_PATTERNS = 748 | 749 | # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be 750 | # searched for input files to be used with the \include or \dontinclude 751 | # commands irrespective of the value of the RECURSIVE tag. 752 | # Possible values are YES and NO. If left blank NO is used. 753 | 754 | EXAMPLE_RECURSIVE = NO 755 | 756 | # The IMAGE_PATH tag can be used to specify one or more files or 757 | # directories that contain image that are included in the documentation (see 758 | # the \image command). 759 | 760 | IMAGE_PATH = 761 | 762 | # The INPUT_FILTER tag can be used to specify a program that doxygen should 763 | # invoke to filter for each input file. Doxygen will invoke the filter program 764 | # by executing (via popen()) the command , where 765 | # is the value of the INPUT_FILTER tag, and is the name of an 766 | # input file. Doxygen will then use the output that the filter program writes 767 | # to standard output. If FILTER_PATTERNS is specified, this tag will be 768 | # ignored. 769 | 770 | INPUT_FILTER = 771 | 772 | # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern 773 | # basis. Doxygen will compare the file name with each pattern and apply the 774 | # filter if there is a match. The filters are a list of the form: 775 | # pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further 776 | # info on how filters are used. If FILTER_PATTERNS is empty or if 777 | # non of the patterns match the file name, INPUT_FILTER is applied. 778 | 779 | FILTER_PATTERNS = 780 | 781 | # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using 782 | # INPUT_FILTER) will be used to filter the input files when producing source 783 | # files to browse (i.e. when SOURCE_BROWSER is set to YES). 784 | 785 | FILTER_SOURCE_FILES = YES 786 | 787 | # The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file 788 | # pattern. A pattern will override the setting for FILTER_PATTERN (if any) 789 | # and it is also possible to disable source filtering for a specific pattern 790 | # using *.ext= (so without naming a filter). This option only has effect when 791 | # FILTER_SOURCE_FILES is enabled. 792 | 793 | FILTER_SOURCE_PATTERNS = 794 | 795 | #--------------------------------------------------------------------------- 796 | # configuration options related to source browsing 797 | #--------------------------------------------------------------------------- 798 | 799 | # If the SOURCE_BROWSER tag is set to YES then a list of source files will 800 | # be generated. Documented entities will be cross-referenced with these sources. 801 | # Note: To get rid of all source code in the generated output, make sure also 802 | # VERBATIM_HEADERS is set to NO. 803 | 804 | SOURCE_BROWSER = NO 805 | 806 | # Setting the INLINE_SOURCES tag to YES will include the body 807 | # of functions and classes directly in the documentation. 808 | 809 | INLINE_SOURCES = NO 810 | 811 | # Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct 812 | # doxygen to hide any special comment blocks from generated source code 813 | # fragments. Normal C and C++ comments will always remain visible. 814 | 815 | STRIP_CODE_COMMENTS = YES 816 | 817 | # If the REFERENCED_BY_RELATION tag is set to YES 818 | # then for each documented function all documented 819 | # functions referencing it will be listed. 820 | 821 | REFERENCED_BY_RELATION = YES 822 | 823 | # If the REFERENCES_RELATION tag is set to YES 824 | # then for each documented function all documented entities 825 | # called/used by that function will be listed. 826 | 827 | REFERENCES_RELATION = YES 828 | 829 | # If the REFERENCES_LINK_SOURCE tag is set to YES (the default) 830 | # and SOURCE_BROWSER tag is set to YES, then the hyperlinks from 831 | # functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will 832 | # link to the source code. Otherwise they will link to the documentation. 833 | 834 | REFERENCES_LINK_SOURCE = YES 835 | 836 | # If the USE_HTAGS tag is set to YES then the references to source code 837 | # will point to the HTML generated by the htags(1) tool instead of doxygen 838 | # built-in source browser. The htags tool is part of GNU's global source 839 | # tagging system (see http://www.gnu.org/software/global/global.html). You 840 | # will need version 4.8.6 or higher. 841 | 842 | USE_HTAGS = NO 843 | 844 | # If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen 845 | # will generate a verbatim copy of the header file for each class for 846 | # which an include is specified. Set to NO to disable this. 847 | 848 | VERBATIM_HEADERS = NO 849 | 850 | #--------------------------------------------------------------------------- 851 | # configuration options related to the alphabetical class index 852 | #--------------------------------------------------------------------------- 853 | 854 | # If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index 855 | # of all compounds will be generated. Enable this if the project 856 | # contains a lot of classes, structs, unions or interfaces. 857 | 858 | ALPHABETICAL_INDEX = YES 859 | 860 | # If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then 861 | # the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns 862 | # in which this list will be split (can be a number in the range [1..20]) 863 | 864 | COLS_IN_ALPHA_INDEX = 3 865 | 866 | # In case all classes in a project start with a common prefix, all 867 | # classes will be put under the same header in the alphabetical index. 868 | # The IGNORE_PREFIX tag can be used to specify one or more prefixes that 869 | # should be ignored while generating the index headers. 870 | 871 | IGNORE_PREFIX = 872 | 873 | #--------------------------------------------------------------------------- 874 | # configuration options related to the HTML output 875 | #--------------------------------------------------------------------------- 876 | 877 | # If the GENERATE_HTML tag is set to YES (the default) Doxygen will 878 | # generate HTML output. 879 | 880 | GENERATE_HTML = YES 881 | 882 | # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. 883 | # If a relative path is entered the value of OUTPUT_DIRECTORY will be 884 | # put in front of it. If left blank `html' will be used as the default path. 885 | 886 | HTML_OUTPUT = html 887 | 888 | # The HTML_FILE_EXTENSION tag can be used to specify the file extension for 889 | # each generated HTML page (for example: .htm,.php,.asp). If it is left blank 890 | # doxygen will generate files with .html extension. 891 | 892 | HTML_FILE_EXTENSION = .html 893 | 894 | # The HTML_HEADER tag can be used to specify a personal HTML header for 895 | # each generated HTML page. If it is left blank doxygen will generate a 896 | # standard header. Note that when using a custom header you are responsible 897 | # for the proper inclusion of any scripts and style sheets that doxygen 898 | # needs, which is dependent on the configuration options used. 899 | # It is advised to generate a default header using "doxygen -w html 900 | # header.html footer.html stylesheet.css YourConfigFile" and then modify 901 | # that header. Note that the header is subject to change so you typically 902 | # have to redo this when upgrading to a newer version of doxygen or when 903 | # changing the value of configuration settings such as GENERATE_TREEVIEW! 904 | 905 | HTML_HEADER = 906 | 907 | # The HTML_FOOTER tag can be used to specify a personal HTML footer for 908 | # each generated HTML page. If it is left blank doxygen will generate a 909 | # standard footer. 910 | 911 | HTML_FOOTER = 912 | 913 | # The HTML_STYLESHEET tag can be used to specify a user-defined cascading 914 | # style sheet that is used by each HTML page. It can be used to 915 | # fine-tune the look of the HTML output. If the tag is left blank doxygen 916 | # will generate a default style sheet. Note that doxygen will try to copy 917 | # the style sheet file to the HTML output directory, so don't put your own 918 | # style sheet in the HTML output directory as well, or it will be erased! 919 | 920 | HTML_STYLESHEET = 921 | 922 | # The HTML_EXTRA_FILES tag can be used to specify one or more extra images or 923 | # other source files which should be copied to the HTML output directory. Note 924 | # that these files will be copied to the base HTML output directory. Use the 925 | # $relpath$ marker in the HTML_HEADER and/or HTML_FOOTER files to load these 926 | # files. In the HTML_STYLESHEET file, use the file name only. Also note that 927 | # the files will be copied as-is; there are no commands or markers available. 928 | 929 | HTML_EXTRA_FILES = 930 | 931 | # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. 932 | # Doxygen will adjust the colors in the style sheet and background images 933 | # according to this color. Hue is specified as an angle on a colorwheel, 934 | # see http://en.wikipedia.org/wiki/Hue for more information. 935 | # For instance the value 0 represents red, 60 is yellow, 120 is green, 936 | # 180 is cyan, 240 is blue, 300 purple, and 360 is red again. 937 | # The allowed range is 0 to 359. 938 | 939 | HTML_COLORSTYLE_HUE = 220 940 | 941 | # The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of 942 | # the colors in the HTML output. For a value of 0 the output will use 943 | # grayscales only. A value of 255 will produce the most vivid colors. 944 | 945 | HTML_COLORSTYLE_SAT = 100 946 | 947 | # The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to 948 | # the luminance component of the colors in the HTML output. Values below 949 | # 100 gradually make the output lighter, whereas values above 100 make 950 | # the output darker. The value divided by 100 is the actual gamma applied, 951 | # so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2, 952 | # and 100 does not change the gamma. 953 | 954 | HTML_COLORSTYLE_GAMMA = 80 955 | 956 | # If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML 957 | # page will contain the date and time when the page was generated. Setting 958 | # this to NO can help when comparing the output of multiple runs. 959 | 960 | HTML_TIMESTAMP = YES 961 | 962 | # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML 963 | # documentation will contain sections that can be hidden and shown after the 964 | # page has loaded. 965 | 966 | HTML_DYNAMIC_SECTIONS = YES 967 | 968 | # With HTML_INDEX_NUM_ENTRIES one can control the preferred number of 969 | # entries shown in the various tree structured indices initially; the user 970 | # can expand and collapse entries dynamically later on. Doxygen will expand 971 | # the tree to such a level that at most the specified number of entries are 972 | # visible (unless a fully collapsed tree already exceeds this amount). 973 | # So setting the number of entries 1 will produce a full collapsed tree by 974 | # default. 0 is a special value representing an infinite number of entries 975 | # and will result in a full expanded tree by default. 976 | 977 | HTML_INDEX_NUM_ENTRIES = 100 978 | 979 | # If the GENERATE_DOCSET tag is set to YES, additional index files 980 | # will be generated that can be used as input for Apple's Xcode 3 981 | # integrated development environment, introduced with OSX 10.5 (Leopard). 982 | # To create a documentation set, doxygen will generate a Makefile in the 983 | # HTML output directory. Running make will produce the docset in that 984 | # directory and running "make install" will install the docset in 985 | # ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find 986 | # it at startup. 987 | # See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html 988 | # for more information. 989 | 990 | GENERATE_DOCSET = NO 991 | 992 | # When GENERATE_DOCSET tag is set to YES, this tag determines the name of the 993 | # feed. A documentation feed provides an umbrella under which multiple 994 | # documentation sets from a single provider (such as a company or product suite) 995 | # can be grouped. 996 | 997 | DOCSET_FEEDNAME = "Doxygen generated docs" 998 | 999 | # When GENERATE_DOCSET tag is set to YES, this tag specifies a string that 1000 | # should uniquely identify the documentation set bundle. This should be a 1001 | # reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen 1002 | # will append .docset to the name. 1003 | 1004 | DOCSET_BUNDLE_ID = org.doxygen.Project 1005 | 1006 | # When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify 1007 | # the documentation publisher. This should be a reverse domain-name style 1008 | # string, e.g. com.mycompany.MyDocSet.documentation. 1009 | 1010 | DOCSET_PUBLISHER_ID = org.doxygen.Publisher 1011 | 1012 | # The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher. 1013 | 1014 | DOCSET_PUBLISHER_NAME = Publisher 1015 | 1016 | # If the GENERATE_HTMLHELP tag is set to YES, additional index files 1017 | # will be generated that can be used as input for tools like the 1018 | # Microsoft HTML help workshop to generate a compiled HTML help file (.chm) 1019 | # of the generated HTML documentation. 1020 | 1021 | GENERATE_HTMLHELP = NO 1022 | 1023 | # If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can 1024 | # be used to specify the file name of the resulting .chm file. You 1025 | # can add a path in front of the file if the result should not be 1026 | # written to the html output directory. 1027 | 1028 | CHM_FILE = 1029 | 1030 | # If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can 1031 | # be used to specify the location (absolute path including file name) of 1032 | # the HTML help compiler (hhc.exe). If non-empty doxygen will try to run 1033 | # the HTML help compiler on the generated index.hhp. 1034 | 1035 | HHC_LOCATION = 1036 | 1037 | # If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag 1038 | # controls if a separate .chi index file is generated (YES) or that 1039 | # it should be included in the master .chm file (NO). 1040 | 1041 | GENERATE_CHI = NO 1042 | 1043 | # If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING 1044 | # is used to encode HtmlHelp index (hhk), content (hhc) and project file 1045 | # content. 1046 | 1047 | CHM_INDEX_ENCODING = 1048 | 1049 | # If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag 1050 | # controls whether a binary table of contents is generated (YES) or a 1051 | # normal table of contents (NO) in the .chm file. 1052 | 1053 | BINARY_TOC = NO 1054 | 1055 | # The TOC_EXPAND flag can be set to YES to add extra items for group members 1056 | # to the contents of the HTML help documentation and to the tree view. 1057 | 1058 | TOC_EXPAND = NO 1059 | 1060 | # If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and 1061 | # QHP_VIRTUAL_FOLDER are set, an additional index file will be generated 1062 | # that can be used as input for Qt's qhelpgenerator to generate a 1063 | # Qt Compressed Help (.qch) of the generated HTML documentation. 1064 | 1065 | GENERATE_QHP = NO 1066 | 1067 | # If the QHG_LOCATION tag is specified, the QCH_FILE tag can 1068 | # be used to specify the file name of the resulting .qch file. 1069 | # The path specified is relative to the HTML output folder. 1070 | 1071 | QCH_FILE = 1072 | 1073 | # The QHP_NAMESPACE tag specifies the namespace to use when generating 1074 | # Qt Help Project output. For more information please see 1075 | # http://doc.trolltech.com/qthelpproject.html#namespace 1076 | 1077 | QHP_NAMESPACE = org.doxygen.Project 1078 | 1079 | # The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating 1080 | # Qt Help Project output. For more information please see 1081 | # http://doc.trolltech.com/qthelpproject.html#virtual-folders 1082 | 1083 | QHP_VIRTUAL_FOLDER = doc 1084 | 1085 | # If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to 1086 | # add. For more information please see 1087 | # http://doc.trolltech.com/qthelpproject.html#custom-filters 1088 | 1089 | QHP_CUST_FILTER_NAME = 1090 | 1091 | # The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the 1092 | # custom filter to add. For more information please see 1093 | # 1094 | # Qt Help Project / Custom Filters. 1095 | 1096 | QHP_CUST_FILTER_ATTRS = 1097 | 1098 | # The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this 1099 | # project's 1100 | # filter section matches. 1101 | # 1102 | # Qt Help Project / Filter Attributes. 1103 | 1104 | QHP_SECT_FILTER_ATTRS = 1105 | 1106 | # If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can 1107 | # be used to specify the location of Qt's qhelpgenerator. 1108 | # If non-empty doxygen will try to run qhelpgenerator on the generated 1109 | # .qhp file. 1110 | 1111 | QHG_LOCATION = 1112 | 1113 | # If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files 1114 | # will be generated, which together with the HTML files, form an Eclipse help 1115 | # plugin. To install this plugin and make it available under the help contents 1116 | # menu in Eclipse, the contents of the directory containing the HTML and XML 1117 | # files needs to be copied into the plugins directory of eclipse. The name of 1118 | # the directory within the plugins directory should be the same as 1119 | # the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before 1120 | # the help appears. 1121 | 1122 | GENERATE_ECLIPSEHELP = NO 1123 | 1124 | # A unique identifier for the eclipse help plugin. When installing the plugin 1125 | # the directory name containing the HTML and XML files should also have 1126 | # this name. 1127 | 1128 | ECLIPSE_DOC_ID = org.doxygen.Project 1129 | 1130 | # The DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) 1131 | # at top of each HTML page. The value NO (the default) enables the index and 1132 | # the value YES disables it. Since the tabs have the same information as the 1133 | # navigation tree you can set this option to NO if you already set 1134 | # GENERATE_TREEVIEW to YES. 1135 | 1136 | DISABLE_INDEX = NO 1137 | 1138 | # The GENERATE_TREEVIEW tag is used to specify whether a tree-like index 1139 | # structure should be generated to display hierarchical information. 1140 | # If the tag value is set to YES, a side panel will be generated 1141 | # containing a tree-like index structure (just like the one that 1142 | # is generated for HTML Help). For this to work a browser that supports 1143 | # JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). 1144 | # Windows users are probably better off using the HTML help feature. 1145 | # Since the tree basically has the same information as the tab index you 1146 | # could consider to set DISABLE_INDEX to NO when enabling this option. 1147 | 1148 | GENERATE_TREEVIEW = NO 1149 | 1150 | # The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values 1151 | # (range [0,1..20]) that doxygen will group on one line in the generated HTML 1152 | # documentation. Note that a value of 0 will completely suppress the enum 1153 | # values from appearing in the overview section. 1154 | 1155 | ENUM_VALUES_PER_LINE = 4 1156 | 1157 | # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be 1158 | # used to set the initial width (in pixels) of the frame in which the tree 1159 | # is shown. 1160 | 1161 | TREEVIEW_WIDTH = 320 1162 | 1163 | # When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open 1164 | # links to external symbols imported via tag files in a separate window. 1165 | 1166 | EXT_LINKS_IN_WINDOW = NO 1167 | 1168 | # Use this tag to change the font size of Latex formulas included 1169 | # as images in the HTML documentation. The default is 10. Note that 1170 | # when you change the font size after a successful doxygen run you need 1171 | # to manually remove any form_*.png images from the HTML output directory 1172 | # to force them to be regenerated. 1173 | 1174 | FORMULA_FONTSIZE = 10 1175 | 1176 | # Use the FORMULA_TRANPARENT tag to determine whether or not the images 1177 | # generated for formulas are transparent PNGs. Transparent PNGs are 1178 | # not supported properly for IE 6.0, but are supported on all modern browsers. 1179 | # Note that when changing this option you need to delete any form_*.png files 1180 | # in the HTML output before the changes have effect. 1181 | 1182 | FORMULA_TRANSPARENT = YES 1183 | 1184 | # Enable the USE_MATHJAX option to render LaTeX formulas using MathJax 1185 | # (see http://www.mathjax.org) which uses client side Javascript for the 1186 | # rendering instead of using prerendered bitmaps. Use this if you do not 1187 | # have LaTeX installed or if you want to formulas look prettier in the HTML 1188 | # output. When enabled you may also need to install MathJax separately and 1189 | # configure the path to it using the MATHJAX_RELPATH option. 1190 | 1191 | USE_MATHJAX = NO 1192 | 1193 | # When MathJax is enabled you need to specify the location relative to the 1194 | # HTML output directory using the MATHJAX_RELPATH option. The destination 1195 | # directory should contain the MathJax.js script. For instance, if the mathjax 1196 | # directory is located at the same level as the HTML output directory, then 1197 | # MATHJAX_RELPATH should be ../mathjax. The default value points to 1198 | # the MathJax Content Delivery Network so you can quickly see the result without 1199 | # installing MathJax. However, it is strongly recommended to install a local 1200 | # copy of MathJax from http://www.mathjax.org before deployment. 1201 | 1202 | MATHJAX_RELPATH = http://www.mathjax.org/mathjax 1203 | 1204 | # The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension 1205 | # names that should be enabled during MathJax rendering. 1206 | 1207 | MATHJAX_EXTENSIONS = 1208 | 1209 | # When the SEARCHENGINE tag is enabled doxygen will generate a search box 1210 | # for the HTML output. The underlying search engine uses javascript 1211 | # and DHTML and should work on any modern browser. Note that when using 1212 | # HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets 1213 | # (GENERATE_DOCSET) there is already a search function so this one should 1214 | # typically be disabled. For large projects the javascript based search engine 1215 | # can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution. 1216 | 1217 | SEARCHENGINE = YES 1218 | 1219 | # When the SERVER_BASED_SEARCH tag is enabled the search engine will be 1220 | # implemented using a PHP enabled web server instead of at the web client 1221 | # using Javascript. Doxygen will generate the search PHP script and index 1222 | # file to put on the web server. The advantage of the server 1223 | # based approach is that it scales better to large projects and allows 1224 | # full text search. The disadvantages are that it is more difficult to setup 1225 | # and does not have live searching capabilities. 1226 | 1227 | SERVER_BASED_SEARCH = NO 1228 | 1229 | #--------------------------------------------------------------------------- 1230 | # configuration options related to the LaTeX output 1231 | #--------------------------------------------------------------------------- 1232 | 1233 | # If the GENERATE_LATEX tag is set to YES (the default) Doxygen will 1234 | # generate Latex output. 1235 | 1236 | GENERATE_LATEX = NO 1237 | 1238 | # The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. 1239 | # If a relative path is entered the value of OUTPUT_DIRECTORY will be 1240 | # put in front of it. If left blank `latex' will be used as the default path. 1241 | 1242 | LATEX_OUTPUT = latex 1243 | 1244 | # The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be 1245 | # invoked. If left blank `latex' will be used as the default command name. 1246 | # Note that when enabling USE_PDFLATEX this option is only used for 1247 | # generating bitmaps for formulas in the HTML output, but not in the 1248 | # Makefile that is written to the output directory. 1249 | 1250 | LATEX_CMD_NAME = latex 1251 | 1252 | # The MAKEINDEX_CMD_NAME tag can be used to specify the command name to 1253 | # generate index for LaTeX. If left blank `makeindex' will be used as the 1254 | # default command name. 1255 | 1256 | MAKEINDEX_CMD_NAME = makeindex 1257 | 1258 | # If the COMPACT_LATEX tag is set to YES Doxygen generates more compact 1259 | # LaTeX documents. This may be useful for small projects and may help to 1260 | # save some trees in general. 1261 | 1262 | COMPACT_LATEX = NO 1263 | 1264 | # The PAPER_TYPE tag can be used to set the paper type that is used 1265 | # by the printer. Possible values are: a4, letter, legal and 1266 | # executive. If left blank a4wide will be used. 1267 | 1268 | PAPER_TYPE = a4wide 1269 | 1270 | # The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX 1271 | # packages that should be included in the LaTeX output. 1272 | 1273 | EXTRA_PACKAGES = 1274 | 1275 | # The LATEX_HEADER tag can be used to specify a personal LaTeX header for 1276 | # the generated latex document. The header should contain everything until 1277 | # the first chapter. If it is left blank doxygen will generate a 1278 | # standard header. Notice: only use this tag if you know what you are doing! 1279 | 1280 | LATEX_HEADER = 1281 | 1282 | # The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for 1283 | # the generated latex document. The footer should contain everything after 1284 | # the last chapter. If it is left blank doxygen will generate a 1285 | # standard footer. Notice: only use this tag if you know what you are doing! 1286 | 1287 | LATEX_FOOTER = 1288 | 1289 | # If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated 1290 | # is prepared for conversion to pdf (using ps2pdf). The pdf file will 1291 | # contain links (just like the HTML output) instead of page references 1292 | # This makes the output suitable for online browsing using a pdf viewer. 1293 | 1294 | PDF_HYPERLINKS = NO 1295 | 1296 | # If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of 1297 | # plain latex in the generated Makefile. Set this option to YES to get a 1298 | # higher quality PDF documentation. 1299 | 1300 | USE_PDFLATEX = NO 1301 | 1302 | # If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. 1303 | # command to the generated LaTeX files. This will instruct LaTeX to keep 1304 | # running if errors occur, instead of asking the user for help. 1305 | # This option is also used when generating formulas in HTML. 1306 | 1307 | LATEX_BATCHMODE = NO 1308 | 1309 | # If LATEX_HIDE_INDICES is set to YES then doxygen will not 1310 | # include the index chapters (such as File Index, Compound Index, etc.) 1311 | # in the output. 1312 | 1313 | LATEX_HIDE_INDICES = NO 1314 | 1315 | # If LATEX_SOURCE_CODE is set to YES then doxygen will include 1316 | # source code with syntax highlighting in the LaTeX output. 1317 | # Note that which sources are shown also depends on other settings 1318 | # such as SOURCE_BROWSER. 1319 | 1320 | LATEX_SOURCE_CODE = NO 1321 | 1322 | # The LATEX_BIB_STYLE tag can be used to specify the style to use for the 1323 | # bibliography, e.g. plainnat, or ieeetr. The default style is "plain". See 1324 | # http://en.wikipedia.org/wiki/BibTeX for more info. 1325 | 1326 | LATEX_BIB_STYLE = plain 1327 | 1328 | #--------------------------------------------------------------------------- 1329 | # configuration options related to the RTF output 1330 | #--------------------------------------------------------------------------- 1331 | 1332 | # If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output 1333 | # The RTF output is optimized for Word 97 and may not look very pretty with 1334 | # other RTF readers or editors. 1335 | 1336 | GENERATE_RTF = NO 1337 | 1338 | # The RTF_OUTPUT tag is used to specify where the RTF docs will be put. 1339 | # If a relative path is entered the value of OUTPUT_DIRECTORY will be 1340 | # put in front of it. If left blank `rtf' will be used as the default path. 1341 | 1342 | RTF_OUTPUT = rtf 1343 | 1344 | # If the COMPACT_RTF tag is set to YES Doxygen generates more compact 1345 | # RTF documents. This may be useful for small projects and may help to 1346 | # save some trees in general. 1347 | 1348 | COMPACT_RTF = NO 1349 | 1350 | # If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated 1351 | # will contain hyperlink fields. The RTF file will 1352 | # contain links (just like the HTML output) instead of page references. 1353 | # This makes the output suitable for online browsing using WORD or other 1354 | # programs which support those fields. 1355 | # Note: wordpad (write) and others do not support links. 1356 | 1357 | RTF_HYPERLINKS = NO 1358 | 1359 | # Load style sheet definitions from file. Syntax is similar to doxygen's 1360 | # config file, i.e. a series of assignments. You only have to provide 1361 | # replacements, missing definitions are set to their default value. 1362 | 1363 | RTF_STYLESHEET_FILE = 1364 | 1365 | # Set optional variables used in the generation of an rtf document. 1366 | # Syntax is similar to doxygen's config file. 1367 | 1368 | RTF_EXTENSIONS_FILE = 1369 | 1370 | #--------------------------------------------------------------------------- 1371 | # configuration options related to the man page output 1372 | #--------------------------------------------------------------------------- 1373 | 1374 | # If the GENERATE_MAN tag is set to YES (the default) Doxygen will 1375 | # generate man pages 1376 | 1377 | GENERATE_MAN = NO 1378 | 1379 | # The MAN_OUTPUT tag is used to specify where the man pages will be put. 1380 | # If a relative path is entered the value of OUTPUT_DIRECTORY will be 1381 | # put in front of it. If left blank `man' will be used as the default path. 1382 | 1383 | MAN_OUTPUT = man 1384 | 1385 | # The MAN_EXTENSION tag determines the extension that is added to 1386 | # the generated man pages (default is the subroutine's section .3) 1387 | 1388 | MAN_EXTENSION = .3 1389 | 1390 | # If the MAN_LINKS tag is set to YES and Doxygen generates man output, 1391 | # then it will generate one additional man file for each entity 1392 | # documented in the real man page(s). These additional files 1393 | # only source the real man page, but without them the man command 1394 | # would be unable to find the correct page. The default is NO. 1395 | 1396 | MAN_LINKS = NO 1397 | 1398 | #--------------------------------------------------------------------------- 1399 | # configuration options related to the XML output 1400 | #--------------------------------------------------------------------------- 1401 | 1402 | # If the GENERATE_XML tag is set to YES Doxygen will 1403 | # generate an XML file that captures the structure of 1404 | # the code including all documentation. 1405 | 1406 | GENERATE_XML = NO 1407 | 1408 | # The XML_OUTPUT tag is used to specify where the XML pages will be put. 1409 | # If a relative path is entered the value of OUTPUT_DIRECTORY will be 1410 | # put in front of it. If left blank `xml' will be used as the default path. 1411 | 1412 | XML_OUTPUT = xml 1413 | 1414 | # The XML_SCHEMA tag can be used to specify an XML schema, 1415 | # which can be used by a validating XML parser to check the 1416 | # syntax of the XML files. 1417 | 1418 | XML_SCHEMA = 1419 | 1420 | # The XML_DTD tag can be used to specify an XML DTD, 1421 | # which can be used by a validating XML parser to check the 1422 | # syntax of the XML files. 1423 | 1424 | XML_DTD = 1425 | 1426 | # If the XML_PROGRAMLISTING tag is set to YES Doxygen will 1427 | # dump the program listings (including syntax highlighting 1428 | # and cross-referencing information) to the XML output. Note that 1429 | # enabling this will significantly increase the size of the XML output. 1430 | 1431 | XML_PROGRAMLISTING = YES 1432 | 1433 | #--------------------------------------------------------------------------- 1434 | # configuration options for the AutoGen Definitions output 1435 | #--------------------------------------------------------------------------- 1436 | 1437 | # If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will 1438 | # generate an AutoGen Definitions (see autogen.sf.net) file 1439 | # that captures the structure of the code including all 1440 | # documentation. Note that this feature is still experimental 1441 | # and incomplete at the moment. 1442 | 1443 | GENERATE_AUTOGEN_DEF = NO 1444 | 1445 | #--------------------------------------------------------------------------- 1446 | # configuration options related to the Perl module output 1447 | #--------------------------------------------------------------------------- 1448 | 1449 | # If the GENERATE_PERLMOD tag is set to YES Doxygen will 1450 | # generate a Perl module file that captures the structure of 1451 | # the code including all documentation. Note that this 1452 | # feature is still experimental and incomplete at the 1453 | # moment. 1454 | 1455 | GENERATE_PERLMOD = NO 1456 | 1457 | # If the PERLMOD_LATEX tag is set to YES Doxygen will generate 1458 | # the necessary Makefile rules, Perl scripts and LaTeX code to be able 1459 | # to generate PDF and DVI output from the Perl module output. 1460 | 1461 | PERLMOD_LATEX = NO 1462 | 1463 | # If the PERLMOD_PRETTY tag is set to YES the Perl module output will be 1464 | # nicely formatted so it can be parsed by a human reader. This is useful 1465 | # if you want to understand what is going on. On the other hand, if this 1466 | # tag is set to NO the size of the Perl module output will be much smaller 1467 | # and Perl will parse it just the same. 1468 | 1469 | PERLMOD_PRETTY = YES 1470 | 1471 | # The names of the make variables in the generated doxyrules.make file 1472 | # are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. 1473 | # This is useful so different doxyrules.make files included by the same 1474 | # Makefile don't overwrite each other's variables. 1475 | 1476 | PERLMOD_MAKEVAR_PREFIX = 1477 | 1478 | #--------------------------------------------------------------------------- 1479 | # Configuration options related to the preprocessor 1480 | #--------------------------------------------------------------------------- 1481 | 1482 | # If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will 1483 | # evaluate all C-preprocessor directives found in the sources and include 1484 | # files. 1485 | 1486 | ENABLE_PREPROCESSING = YES 1487 | 1488 | # If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro 1489 | # names in the source code. If set to NO (the default) only conditional 1490 | # compilation will be performed. Macro expansion can be done in a controlled 1491 | # way by setting EXPAND_ONLY_PREDEF to YES. 1492 | 1493 | MACRO_EXPANSION = NO 1494 | 1495 | # If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES 1496 | # then the macro expansion is limited to the macros specified with the 1497 | # PREDEFINED and EXPAND_AS_DEFINED tags. 1498 | 1499 | EXPAND_ONLY_PREDEF = NO 1500 | 1501 | # If the SEARCH_INCLUDES tag is set to YES (the default) the includes files 1502 | # pointed to by INCLUDE_PATH will be searched when a #include is found. 1503 | 1504 | SEARCH_INCLUDES = YES 1505 | 1506 | # The INCLUDE_PATH tag can be used to specify one or more directories that 1507 | # contain include files that are not input files but should be processed by 1508 | # the preprocessor. 1509 | 1510 | INCLUDE_PATH = 1511 | 1512 | # You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard 1513 | # patterns (like *.h and *.hpp) to filter out the header-files in the 1514 | # directories. If left blank, the patterns specified with FILE_PATTERNS will 1515 | # be used. 1516 | 1517 | INCLUDE_FILE_PATTERNS = 1518 | 1519 | # The PREDEFINED tag can be used to specify one or more macro names that 1520 | # are defined before the preprocessor is started (similar to the -D option of 1521 | # gcc). The argument of the tag is a list of macros of the form: name 1522 | # or name=definition (no spaces). If the definition and the = are 1523 | # omitted =1 is assumed. To prevent a macro definition from being 1524 | # undefined via #undef or recursively expanded use the := operator 1525 | # instead of the = operator. 1526 | 1527 | PREDEFINED = WIN32=1 \ 1528 | JUCE_WIN32=1 \ 1529 | JUCE_MAC=1 \ 1530 | JUCE_IOS=1 \ 1531 | JUCE_ANDROID=1 \ 1532 | JUCE_LINUX=1 \ 1533 | DOXYGEN=1 \ 1534 | JUCE_COMPILER_SUPPORTS_NOEXCEPT=1 \ 1535 | JUCE_COMPILER_SUPPORTS_NULLPTR=1 \ 1536 | JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS=1 \ 1537 | JUCE_COMPILER_SUPPORTS_INITIALIZER_LISTS=1 \ 1538 | JUCE_COMPILER_SUPPORTS_VARIADIC_TEMPLATES=1 \ 1539 | JUCE_COMPILER_SUPPORTS_OVERRIDE_AND_FINAL=1 \ 1540 | JUCE_MODAL_LOOPS_PERMITTED=1 1541 | 1542 | # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then 1543 | # this tag can be used to specify a list of macro names that should be expanded. 1544 | # The macro definition that is found in the sources will be used. 1545 | # Use the PREDEFINED tag if you want to use a different macro definition that 1546 | # overrules the definition found in the source code. 1547 | 1548 | EXPAND_AS_DEFINED = 1549 | 1550 | # If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then 1551 | # doxygen's preprocessor will remove all references to function-like macros 1552 | # that are alone on a line, have an all uppercase name, and do not end with a 1553 | # semicolon, because these will confuse the parser if not removed. 1554 | 1555 | SKIP_FUNCTION_MACROS = YES 1556 | 1557 | #--------------------------------------------------------------------------- 1558 | # Configuration::additions related to external references 1559 | #--------------------------------------------------------------------------- 1560 | 1561 | # The TAGFILES option can be used to specify one or more tagfiles. For each 1562 | # tag file the location of the external documentation should be added. The 1563 | # format of a tag file without this location is as follows: 1564 | # TAGFILES = file1 file2 ... 1565 | # Adding location for the tag files is done as follows: 1566 | # TAGFILES = file1=loc1 "file2 = loc2" ... 1567 | # where "loc1" and "loc2" can be relative or absolute paths 1568 | # or URLs. Note that each tag file must have a unique name (where the name does 1569 | # NOT include the path). If a tag file is not located in the directory in which 1570 | # doxygen is run, you must also specify the path to the tagfile here. 1571 | 1572 | TAGFILES = 1573 | 1574 | # When a file name is specified after GENERATE_TAGFILE, doxygen will create 1575 | # a tag file that is based on the input files it reads. 1576 | 1577 | GENERATE_TAGFILE = 1578 | 1579 | # If the ALLEXTERNALS tag is set to YES all external classes will be listed 1580 | # in the class index. If set to NO only the inherited external classes 1581 | # will be listed. 1582 | 1583 | ALLEXTERNALS = NO 1584 | 1585 | # If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed 1586 | # in the modules index. If set to NO, only the current project's groups will 1587 | # be listed. 1588 | 1589 | EXTERNAL_GROUPS = YES 1590 | 1591 | # The PERL_PATH should be the absolute path and name of the perl script 1592 | # interpreter (i.e. the result of `which perl'). 1593 | 1594 | PERL_PATH = /usr/bin/perl 1595 | 1596 | #--------------------------------------------------------------------------- 1597 | # Configuration options related to the dot tool 1598 | #--------------------------------------------------------------------------- 1599 | 1600 | # If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will 1601 | # generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base 1602 | # or super classes. Setting the tag to NO turns the diagrams off. Note that 1603 | # this option also works with HAVE_DOT disabled, but it is recommended to 1604 | # install and use dot, since it yields more powerful graphs. 1605 | 1606 | CLASS_DIAGRAMS = YES 1607 | 1608 | # You can define message sequence charts within doxygen comments using the \msc 1609 | # command. Doxygen will then run the mscgen tool (see 1610 | # http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the 1611 | # documentation. The MSCGEN_PATH tag allows you to specify the directory where 1612 | # the mscgen tool resides. If left empty the tool is assumed to be found in the 1613 | # default search path. 1614 | 1615 | MSCGEN_PATH = 1616 | 1617 | # If set to YES, the inheritance and collaboration graphs will hide 1618 | # inheritance and usage relations if the target is undocumented 1619 | # or is not a class. 1620 | 1621 | HIDE_UNDOC_RELATIONS = YES 1622 | 1623 | # If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is 1624 | # available from the path. This tool is part of Graphviz, a graph visualization 1625 | # toolkit from AT&T and Lucent Bell Labs. The other options in this section 1626 | # have no effect if this option is set to NO (the default) 1627 | 1628 | HAVE_DOT = NO 1629 | 1630 | # The DOT_NUM_THREADS specifies the number of dot invocations doxygen is 1631 | # allowed to run in parallel. When set to 0 (the default) doxygen will 1632 | # base this on the number of processors available in the system. You can set it 1633 | # explicitly to a value larger than 0 to get control over the balance 1634 | # between CPU load and processing speed. 1635 | 1636 | DOT_NUM_THREADS = 0 1637 | 1638 | # By default doxygen will use the Helvetica font for all dot files that 1639 | # doxygen generates. When you want a differently looking font you can specify 1640 | # the font name using DOT_FONTNAME. You need to make sure dot is able to find 1641 | # the font, which can be done by putting it in a standard location or by setting 1642 | # the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the 1643 | # directory containing the font. 1644 | 1645 | DOT_FONTNAME = Helvetica 1646 | 1647 | # The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. 1648 | # The default size is 10pt. 1649 | 1650 | DOT_FONTSIZE = 10 1651 | 1652 | # By default doxygen will tell dot to use the Helvetica font. 1653 | # If you specify a different font using DOT_FONTNAME you can use DOT_FONTPATH to 1654 | # set the path where dot can find it. 1655 | 1656 | DOT_FONTPATH = 1657 | 1658 | # If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen 1659 | # will generate a graph for each documented class showing the direct and 1660 | # indirect inheritance relations. Setting this tag to YES will force the 1661 | # CLASS_DIAGRAMS tag to NO. 1662 | 1663 | CLASS_GRAPH = YES 1664 | 1665 | # If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen 1666 | # will generate a graph for each documented class showing the direct and 1667 | # indirect implementation dependencies (inheritance, containment, and 1668 | # class references variables) of the class with other documented classes. 1669 | 1670 | COLLABORATION_GRAPH = NO 1671 | 1672 | # If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen 1673 | # will generate a graph for groups, showing the direct groups dependencies 1674 | 1675 | GROUP_GRAPHS = NO 1676 | 1677 | # If the UML_LOOK tag is set to YES doxygen will generate inheritance and 1678 | # collaboration diagrams in a style similar to the OMG's Unified Modeling 1679 | # Language. 1680 | 1681 | UML_LOOK = NO 1682 | 1683 | # If the UML_LOOK tag is enabled, the fields and methods are shown inside 1684 | # the class node. If there are many fields or methods and many nodes the 1685 | # graph may become too big to be useful. The UML_LIMIT_NUM_FIELDS 1686 | # threshold limits the number of items for each type to make the size more 1687 | # managable. Set this to 0 for no limit. Note that the threshold may be 1688 | # exceeded by 50% before the limit is enforced. 1689 | 1690 | UML_LIMIT_NUM_FIELDS = 10 1691 | 1692 | # If set to YES, the inheritance and collaboration graphs will show the 1693 | # relations between templates and their instances. 1694 | 1695 | TEMPLATE_RELATIONS = NO 1696 | 1697 | # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT 1698 | # tags are set to YES then doxygen will generate a graph for each documented 1699 | # file showing the direct and indirect include dependencies of the file with 1700 | # other documented files. 1701 | 1702 | INCLUDE_GRAPH = NO 1703 | 1704 | # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and 1705 | # HAVE_DOT tags are set to YES then doxygen will generate a graph for each 1706 | # documented header file showing the documented files that directly or 1707 | # indirectly include this file. 1708 | 1709 | INCLUDED_BY_GRAPH = NO 1710 | 1711 | # If the CALL_GRAPH and HAVE_DOT options are set to YES then 1712 | # doxygen will generate a call dependency graph for every global function 1713 | # or class method. Note that enabling this option will significantly increase 1714 | # the time of a run. So in most cases it will be better to enable call graphs 1715 | # for selected functions only using the \callgraph command. 1716 | 1717 | CALL_GRAPH = NO 1718 | 1719 | # If the CALLER_GRAPH and HAVE_DOT tags are set to YES then 1720 | # doxygen will generate a caller dependency graph for every global function 1721 | # or class method. Note that enabling this option will significantly increase 1722 | # the time of a run. So in most cases it will be better to enable caller 1723 | # graphs for selected functions only using the \callergraph command. 1724 | 1725 | CALLER_GRAPH = NO 1726 | 1727 | # If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen 1728 | # will generate a graphical hierarchy of all classes instead of a textual one. 1729 | 1730 | GRAPHICAL_HIERARCHY = NO 1731 | 1732 | # If the DIRECTORY_GRAPH and HAVE_DOT tags are set to YES 1733 | # then doxygen will show the dependencies a directory has on other directories 1734 | # in a graphical way. The dependency relations are determined by the #include 1735 | # relations between the files in the directories. 1736 | 1737 | DIRECTORY_GRAPH = NO 1738 | 1739 | # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images 1740 | # generated by dot. Possible values are svg, png, jpg, or gif. 1741 | # If left blank png will be used. If you choose svg you need to set 1742 | # HTML_FILE_EXTENSION to xhtml in order to make the SVG files 1743 | # visible in IE 9+ (other browsers do not have this requirement). 1744 | 1745 | DOT_IMAGE_FORMAT = png 1746 | 1747 | # If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to 1748 | # enable generation of interactive SVG images that allow zooming and panning. 1749 | # Note that this requires a modern browser other than Internet Explorer. 1750 | # Tested and working are Firefox, Chrome, Safari, and Opera. For IE 9+ you 1751 | # need to set HTML_FILE_EXTENSION to xhtml in order to make the SVG files 1752 | # visible. Older versions of IE do not have SVG support. 1753 | 1754 | INTERACTIVE_SVG = NO 1755 | 1756 | # The tag DOT_PATH can be used to specify the path where the dot tool can be 1757 | # found. If left blank, it is assumed the dot tool can be found in the path. 1758 | 1759 | DOT_PATH = 1760 | 1761 | # The DOTFILE_DIRS tag can be used to specify one or more directories that 1762 | # contain dot files that are included in the documentation (see the 1763 | # \dotfile command). 1764 | 1765 | DOTFILE_DIRS = 1766 | 1767 | # The MSCFILE_DIRS tag can be used to specify one or more directories that 1768 | # contain msc files that are included in the documentation (see the 1769 | # \mscfile command). 1770 | 1771 | MSCFILE_DIRS = 1772 | 1773 | # The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of 1774 | # nodes that will be shown in the graph. If the number of nodes in a graph 1775 | # becomes larger than this value, doxygen will truncate the graph, which is 1776 | # visualized by representing a node as a red box. Note that doxygen if the 1777 | # number of direct children of the root node in a graph is already larger than 1778 | # DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note 1779 | # that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. 1780 | 1781 | DOT_GRAPH_MAX_NODES = 50 1782 | 1783 | # The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the 1784 | # graphs generated by dot. A depth value of 3 means that only nodes reachable 1785 | # from the root by following a path via at most 3 edges will be shown. Nodes 1786 | # that lay further from the root node will be omitted. Note that setting this 1787 | # option to 1 or 2 may greatly reduce the computation time needed for large 1788 | # code bases. Also note that the size of a graph can be further restricted by 1789 | # DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. 1790 | 1791 | MAX_DOT_GRAPH_DEPTH = 0 1792 | 1793 | # Set the DOT_TRANSPARENT tag to YES to generate images with a transparent 1794 | # background. This is disabled by default, because dot on Windows does not 1795 | # seem to support this out of the box. Warning: Depending on the platform used, 1796 | # enabling this option may lead to badly anti-aliased labels on the edges of 1797 | # a graph (i.e. they become hard to read). 1798 | 1799 | DOT_TRANSPARENT = NO 1800 | 1801 | # Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output 1802 | # files in one run (i.e. multiple -o and -T options on the command line). This 1803 | # makes dot run faster, but since only newer versions of dot (>1.8.10) 1804 | # support this, this feature is disabled by default. 1805 | 1806 | DOT_MULTI_TARGETS = NO 1807 | 1808 | # If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will 1809 | # generate a legend page explaining the meaning of the various boxes and 1810 | # arrows in the dot generated graphs. 1811 | 1812 | GENERATE_LEGEND = YES 1813 | 1814 | # If the DOT_CLEANUP tag is set to YES (the default) Doxygen will 1815 | # remove the intermediate dot files that are used to generate 1816 | # the various graphs. 1817 | 1818 | DOT_CLEANUP = YES 1819 | --------------------------------------------------------------------------------