HISE Logo Forum
    • Categories
    • Register
    • Login

    Best Practice for Getting RMS/Peak on an audio buffer

    Scheduled Pinned Locked Moved General Questions
    11 Posts 4 Posters 552 Views
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • mmprodM
      mmprod @Noahdeetz
      last edited by

      @Noahdeetz Did you figure out how to do this?

      For God so loved the world that he gave his one and only Son, that whoever believes in him shall not perish but have eternal life.
      John 3:16

      griffinboyG 1 Reply Last reply Reply Quote 0
      • griffinboyG
        griffinboy @mmprod
        last edited by griffinboy

        @mmprod

        I think there is a working post on this. If you look for rms in the docs there are some instructions. If you need to get rms from a specific point in scriptnode, I can give you one of my c++ nodes for scriptnode which has a mod output for rms.

        mmprodM 1 Reply Last reply Reply Quote 0
        • mmprodM
          mmprod @griffinboy
          last edited by

          @griffinboy ooh yes— that’s exactly what I need!

          For God so loved the world that he gave his one and only Son, that whoever believes in him shall not perish but have eternal life.
          John 3:16

          griffinboyG 1 Reply Last reply Reply Quote 0
          • griffinboyG
            griffinboy @mmprod
            last edited by griffinboy

            @mmprod

            Create a file called Griffin_Rms.h and paste the following code into it. Place the file in your Hise project under:
            DspNetworks > ThridParty

            Open your hise project and under export, choose 'compile dsp networks as dll' Upon completion you can restart hise and you will be able to use the node in scriptnode, find it under the 'projects' category when you open a new node in scriptnode.

            Feel free to experiment with the code, most of the functionality should be self explanatory, and if you give chat gpt the code, you can ask it to explain each part.

            #pragma once
            #include <JuceHeader.h>
            #include <cmath>
            
            namespace project
            {
                using namespace juce;
                using namespace hise;
                using namespace scriptnode;
            
                template <int NV>
                struct Griffin_Rms : public data::base
                {
                    // Metadata Definitions ------------------------------------------------------------------------
                    SNEX_NODE(Griffin_Rms);
            
                    struct MetadataClass
                    {
                        SN_NODE_ID("Griffin_Rms");
                    };
            
                    // Node Configuration ------------------------------------------------------------------------
                    static constexpr bool isModNode() { return true; }
                    static constexpr bool isPolyphonic() { return NV > 1; }
                    static constexpr bool hasTail() { return false; }
                    static constexpr bool isSuspendedOnSilence() { return true; }
                    static constexpr int getFixChannelAmount() { return NV; }
            
                    static constexpr int NumTables = 0;
                    static constexpr int NumSliderPacks = 0;
                    static constexpr int NumAudioFiles = 0;
                    static constexpr int NumFilters = 0;
                    static constexpr int NumDisplayBuffers = 0;
            
                    // Constants ------------------------------------------------------------------------------------
                    static constexpr double SILENCE_THRESHOLD_RMS = 1e-5;   // Threshold for detecting silence
                    static constexpr double MIN_RMS = 1e-8;                 // Minimum RMS value to prevent log(0)
            
                    // External Parameters -----------------------------------------------------------------------
                    double blockDuration = 0.1;   // Block size in seconds (RMS window duration)
            
                    // Internal Variables ------------------------------------------------------------------------
                    double sampleRate = 44100.0;       // Default sample rate
                    double rmsFilterCoefficient = 0.0; // Filter coefficient for the smoothing filter
                    double currentMeanSquare = 0.0;    // The current mean square value
            
                    ModValue modValue;                // Modulation value handler
            
                    // Preparation and Reset ----------------------------------------------------------------------
                    void prepare(PrepareSpecs prepareSpecs)
                    {
                        sampleRate = prepareSpecs.sampleRate;
                        updateFilterCoefficient();
                        currentMeanSquare = 0.0;
                    }
            
                    void reset()
                    {
                        currentMeanSquare = 0.0;
                    }
            
                    // Helper Functions ---------------------------------------------------------------------------
                    void updateFilterCoefficient()
                    {
                        if (blockDuration <= 0.0)
                            blockDuration = 0.1; // Prevent invalid block duration
            
                        rmsFilterCoefficient = std::exp(-1.0 / (sampleRate * blockDuration));
                    }
            
                    // Processing ---------------------------------------------------------------------------------
                    template <typename ProcessDataType>
                    void process(ProcessDataType& data)
                    {
                        auto& fixData = data.as<ProcessData<getFixChannelAmount()>>();
                        auto audioBlock = fixData.toAudioBlock();
            
                        int numSamples = audioBlock.getNumSamples();
                        int numChannels = audioBlock.getNumChannels();
            
                        for (int i = 0; i < numSamples; ++i)
                        {
                            double sumSquares = 0.0;
                            for (int ch = 0; ch < numChannels; ++ch)
                            {
                                double sample = static_cast<double>(audioBlock.getSample(ch, i));
                                sumSquares += sample * sample;
                            }
            
                            // Compute mean square for current sample across all channels
                            double meanSquare = sumSquares / numChannels;
            
                            // Update the EMA of the mean square (RMS squared)
                            currentMeanSquare = rmsFilterCoefficient * currentMeanSquare + (1.0 - rmsFilterCoefficient) * meanSquare;
            
                            // Compute RMS from mean square
                            double rmsValue = std::sqrt(currentMeanSquare);
            
                            // Silence detection
                            bool isSilent = 0;
                            // bool isSilent = rmsValue < SILENCE_THRESHOLD_RMS;
                            // ^ uncomment this line to enable silence detection for rms
                             
                            // Use MIN_RMS to prevent log(0)
                            double safeRMS = isSilent ? MIN_RMS : rmsValue;
            
                            // Convert own RMS to dB
                            double ownRMS_dB = 20.0 * std::log10(safeRMS);
            
                            // Update modulation value with the RMS in dB
                            modValue.setModValue(static_cast<float>(ownRMS_dB));
                        }
                    }
            
                    // Modulation Handling ------------------------------------------------------------------------
                    int handleModulation(double& value)
                    {
                        return modValue.getChangedValue(value);
                    }
            
                    // External Data and Events --------------------------------------------------------------------
                    void setExternalData(const ExternalData& data, int index) {}
                    void handleHiseEvent(HiseEvent& e) {}
            
                    // Frame Processing ----------------------------------------------------------------------------
                    template <typename T>
                    void processFrame(T& data) noexcept {}
            
                    // Parameter Setting ---------------------------------------------------------------------------
                    template <int P>
                    void setParameter(double v)
                    {
                        if (P == 0)
                        {
                            // Block Duration parameter
                            blockDuration = v;
                            updateFilterCoefficient();
                            reset();
                        }
                    }
            
                    // Create Parameters on the GUI -----------------------------------------------------------------
                    void createParameters(ParameterDataList& data)
                    {
                        {
                            parameter::data p("Block Size (s)", { 0.01, 3.0, 0.01 });
                            registerCallback<0>(p);
                            p.setDefaultValue(0.02);
                            data.add(std::move(p));
                        }
                    }
                };
            }
            
            C 1 Reply Last reply Reply Quote 2
            • C
              Consint @griffinboy
              last edited by

              @griffinboy Many thanks also for this node. Unfortunately, I get this error message when compiling and don't know what to do with it:

              ../../Source/../../ThirdParty/Griffin_Rms.h:75:70: error: expected primary-expression before ‘>’ token
                 75 |          auto& fixData = data.as<ProcessData<getFixChannelAmount()>>();
              

              Do you (or anyone else) have any idea why this might be?

              griffinboyG 1 Reply Last reply Reply Quote 0
              • griffinboyG
                griffinboy @Consint
                last edited by

                @Consint ah that's an ancient version I can give a more updated version

                C 1 Reply Last reply Reply Quote 1
                • C
                  Consint @griffinboy
                  last edited by

                  @griffinboy That would be amazing!

                  griffinboyG 1 Reply Last reply Reply Quote 0
                  • griffinboyG
                    griffinboy @Consint
                    last edited by

                    @Consint

                    https://1drv.ms/f/c/6c19b197e5968b36/EmZ5h1zjnU1KrUgMY9IlSL4BAwW4hzauqH0e51ZpNr-Sjw?e=t9HbSA

                    C 1 Reply Last reply Reply Quote 1
                    • C
                      Consint @griffinboy
                      last edited by

                      @griffinboy That's fantastic, thank you very much!

                      griffinboyG 1 Reply Last reply Reply Quote 0
                      • griffinboyG
                        griffinboy @Consint
                        last edited by

                        @Consint

                        let me know if there are any issues:
                        I haven't released this version yet officially becuase i haven't had the time to thoroughly test it

                        1 Reply Last reply Reply Quote 1
                        • First post
                          Last post

                        32

                        Online

                        1.8k

                        Users

                        12.1k

                        Topics

                        104.9k

                        Posts