@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));
}
}
};
}