@ustk
Global cables can be used.
// Griffin_Node.h
// -----------------------------------------------------------------------------
#pragma once
#include <JuceHeader.h>
//#include "src/.h"
//#include "src/.h"
//#include "src/.h"
//#include "src/.h"
//#include "src/Utils_DelayInterpolation.h"
//#include "src/Utils_General.h"
//#include "src/Utils_XSimd.h"
namespace project
{
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
using namespace juce;
using namespace hise;
using namespace scriptnode;
/*
Griffin_Node
-----------
Description of entire program + specs
*/
/*
// Global Cable Example (communicate arbitrary data to Hise)
enum class GlobalCables
{
dataCable = 0
};
using cable_manager_t = routing::global_cable_cpp_manager<SN_GLOBAL_CABLE(-389806413)>;
// Template the node with this
template <int NV> struct Griffin_Node: public data::base,
public cable_manager_t
{
// In c++ we can then:
// create a json object
hise::JSONObject obj;
// write values into the JSON object
obj["thingies"] = [0,1,2,3,4];
// send the object back to HISE
this->sendDataToGlobalCable<GlobalCables::dataCable>(obj);
// thus we can send any type of data to Hise
// then in Hise we can do:
const var rm = Engine.getGlobalRoutingManager();
const var cableName = rm.getCable("cableName");
cableName.registerDataCallback(function(data)
{
Console.print("DATA: " + trace(data));
});
*/
// pre C++20
// You cannot change the way this node is templated
template <int NV>
// name
struct Griffin_Node : public data::base
{ // name
SNEX_NODE(Griffin_Node);
struct MetadataClass
{ // name
SN_NODE_ID("Griffin_Node");
};
// name
Griffin_Node()
{
// Callback for global cables
// (from HISE to your C++ node, this is the way to register callbacks).
//this->registerDataCallback<GlobalCables::dataCable>([](const var& funky)
//{
// jassertfalse;
//});
}
//==============================================================================
// Node Properties
//==============================================================================
static constexpr bool isModNode() { return false; }
static constexpr bool isPolyphonic() { return NV > 1; }
static constexpr bool hasTail() { return false; }
static constexpr bool isSuspendedOnSilence() { return false; }
static constexpr int getFixChannelAmount() { return 2; }
// Add external data slots to the node UI
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;
/*
AudioEffect
-----------
Description
*/
class AudioEffect
{
public:
AudioEffect(float initiaParam = 5000.0f)
{
localParam = initiaParam;
}
// Initialize the effect if needed
void prepare(double sampleRate)
{
}
// Process a block of samples
inline void process(float* samples, int numSamples)
{
// Iterate over the samples
for (int i = 0; i < numSamples; ++i)
{
}
}
// Update the parameters
inline void updateParam1(float newParam)
{
localParam = newParam;
}
private:
float localParam;
};
/*
Main Node
-----------
Description
*/
// Initialize the effect
void prepare(PrepareSpecs specs)
{
float sampleRate = specs.sampleRate;
float numChannels = specs.numChannels;
// Initialize both effects (does nothing by default)
leftChannelEffect.prepare(sampleRate);
rightChannelEffect.prepare(sampleRate);
}
// Reset (called when the plugin is reloaded)
void reset() {}
// Process audio blocks (audio enters the node here)
template <typename PD>
inline void process(PD& d)
{
auto& fix = d.template as<ProcessData<2>>();
auto blk = fix.toAudioBlock();
float* L = blk.getChannelPointer(0);
float* R = blk.getChannelPointer(1);
int n = d.getNumSamples();
// Process each channel separately through their own audioEffect instance
leftChannelEffect.process(L, n);
rightChannelEffect.process(R, n);
}
/*
Parameter Handling
-----------
Description
*/
// Update parameters
template <int P>
inline void setParameter(double v)
{
if (P == 0) {
leftChannelEffect.updateParam1(static_cast<float>(v));
rightChannelEffect.updateParam1(static_cast<float>(v));
}
if (P == 1) {
// Do something with value (v)
}
}
// Create GUI parameters
void createParameters(ParameterDataList& data)
{
{
parameter::data p("Param", { 0.0, 1.0, 0.01 });
registerCallback<0>(p);
p.setDefaultValue(5000.0);
data.add(std::move(p));
}
{
parameter::data p("Param2", { 0.0, 1.0, 0.01 });
registerCallback<0>(p);
p.setDefaultValue(5000.0);
data.add(std::move(p));
}
}
// When this header file gets run for the first time, setParameter gets called with the default knob values
/*
External Data
-----------
Description
*/
// span<dyn<float>, NUM_CHANNELS> externalBuffer;
void setExternalData(const ExternalData& ed, int index)
{
/*
if(data.isNotEmpty())
{
// ExternalData data = ed;
// float audioSampleRate = data.sampleRate;
// float audioNumChannels = data.numChannels;
// float audioNumSamples = data.numSamples;
// ed.referBlockTo(externalBuffer[0], 0);
// ed.referBlockTo(externalBuffer[1], 1);
// Alternatively convert the data to the juce::AudioSampleBuffer class
// auto buffer = data.toAudioSampleBuffer();
}
*/
}
/*
Hise Event
-----------
Description
*/
void handleHiseEvent(HiseEvent& e)
{
/*
if (e.isNoteOn())
{
float note = e.getNoteNumber();
}
*/
}
/*
Modulation Output
-----------
To enable, set isModNode() to true)
*/
// ModValue modOut;
// bool handleModulation(double& value)
// {
// return modOut.getChangedValue(value);
// }
// Use this to call handleModulation
// modOut.setModValueIfChanged( set mod to something );
//==============================================================================
// Unused Functions (Required by compiler)
//==============================================================================
SN_EMPTY_PROCESS_FRAME;
//SN_EMPTY_HANDLE_EVENT;
//SN_EMPTY_SET_EXTERNAL_DATA;
//SN_EMPTY_CREATE_PARAM;
private:
AudioEffect leftChannelEffect;
AudioEffect rightChannelEffect;
};
}