Using LUT on SNEX
-
@Dan-Korneff Lookup Table is what I'm aiming for. It doesn't have to be snex_shaper, snex is fine too.
Is there a small example?
-
@orange I used a document I found by chance in
tools/snex_playground/all/IndexDoc.md
I wonder why such a treasure isn't in the doc, @Christoph-Hart ?There's everything inside to create a LUT and interpolate
-
-
I did something like this:
#pragma once #include <JuceHeader.h> namespace project { using namespace juce; using namespace hise; using namespace scriptnode; // ==========================| The node class with all required callbacks |========================== template <int NV> struct LUT_Test: public data::base { // Metadata Definitions ------------------------------------------------------------------------ SNEX_NODE(LUT_Test); struct MetadataClass { SN_NODE_ID("LUT_Test"); }; // Constants for the Lookup Table -------------------------------------------------------------- static constexpr int tableSize = 200; // The size of the lookup table array static constexpr float xMin = -1.0f; // Minimum input value (start of the input range) static constexpr float xMax = 1.0f; // Maximum input value (end of the input range) static constexpr float xRange = xMax - xMin; // Total range of input values // Lookup Table Data --------------------------------------------------------------------------- static constexpr float lookupTable[tableSize] = { -0.356490f, -0.357427f, -0.358393f, -0.359388f, -0.360412f, -0.361464f, -0.362544f, -0.363653f, -0.364790f, -0.365954f, -0.367146f, -0.368366f, -0.369613f, -0.370887f, -0.372188f, -0.373515f, -0.374870f, -0.376251f, -0.377658f, -0.379091f, -0.380551f, -0.382031f, -0.383487f, -0.384854f, -0.386069f, -0.387067f, -0.387784f, -0.388167f, -0.388236f, -0.388037f, -0.387613f, -0.387010f, -0.386272f, -0.385446f, -0.384574f, -0.383703f, -0.382877f, -0.382142f, -0.381541f, -0.381120f, -0.380925f, -0.380999f, -0.381387f, -0.382135f, -0.383288f, -0.384889f, -0.386944f, -0.389391f, -0.392161f, -0.395186f, -0.398397f, -0.401724f, -0.405101f, -0.408457f, -0.411725f, -0.414835f, -0.417719f, -0.420308f, -0.422534f, -0.424328f, -0.425621f, -0.426345f, -0.426464f, -0.425989f, -0.424939f, -0.423329f, -0.421179f, -0.418503f, -0.415321f, -0.411648f, -0.407502f, -0.402900f, -0.397859f, -0.392396f, -0.386529f, -0.380274f, -0.373649f, -0.366634f, -0.359082f, -0.350815f, -0.341658f, -0.331433f, -0.319963f, -0.307071f, -0.292583f, -0.276464f, -0.258907f, -0.240127f, -0.220341f, -0.199765f, -0.178613f, -0.157102f, -0.135447f, -0.113863f, -0.092567f, -0.071774f, -0.051659f, -0.032214f, -0.013375f, 0.004921f, 0.022736f, 0.040134f, 0.057177f, 0.073928f, 0.090451f, 0.106808f, 0.123062f, 0.139276f, 0.155513f, 0.171836f, 0.188308f, 0.204992f, 0.221950f, 0.239246f, 0.256943f, 0.275078f, 0.293520f, 0.312062f, 0.330498f, 0.348620f, 0.366224f, 0.383101f, 0.399047f, 0.413853f, 0.427315f, 0.439226f, 0.449378f, 0.457566f, 0.463622f, 0.467645f, 0.469852f, 0.470458f, 0.469678f, 0.467729f, 0.464826f, 0.461186f, 0.457023f, 0.452555f, 0.447995f, 0.443562f, 0.439469f, 0.435933f, 0.433164f, 0.431234f, 0.430080f, 0.429634f, 0.429825f, 0.430586f, 0.431847f, 0.433540f, 0.435594f, 0.437942f, 0.440514f, 0.443241f, 0.446055f, 0.448886f, 0.451665f, 0.454324f, 0.456793f, 0.459003f, 0.460886f, 0.462372f, 0.463417f, 0.464063f, 0.464372f, 0.464405f, 0.464224f, 0.463891f, 0.463468f, 0.463016f, 0.462596f, 0.462272f, 0.462104f, 0.462155f, 0.462484f, 0.463117f, 0.464024f, 0.465173f, 0.466533f, 0.468071f, 0.469755f, 0.471553f, 0.473432f, 0.475361f, 0.477308f, 0.479239f, 0.481124f, 0.482929f, 0.484623f, 0.486174f, 0.487549f, 0.488716f, 0.489644f, 0.490299f, 0.490650f, 0.490665f, 0.490311f, 0.489556f, 0.488369f, 0.486716f }; // set to true if you want this node to have a modulation dragger static constexpr bool isModNode() { return false; }; static constexpr bool isPolyphonic() { return NV > 1; }; // set to true if your node produces a tail static constexpr bool hasTail() { return false; }; // set to true if your doesn't generate sound from silence and can be suspended when the input signal is silent static constexpr bool isSuspendedOnSilence() { return false; }; // Undefine this method if you want a dynamic channel count static constexpr int getFixChannelAmount() { return 2; }; // Define the amount and types of external data slots you want to use 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; // Scriptnode Callbacks ------------------------------------------------------------------------ void prepare(PrepareSpecs specs) { // Prepare your node with specifications } void reset() { // Reset any node states } template <typename T> void process(T& data) { static constexpr int NumChannels = getFixChannelAmount(); auto& fixData = data.template as<ProcessData<NumChannels>>(); auto fd = fixData.toFrameData(); while (fd.next()) { processFrame(fd.toSpan()); } } template <typename T> void processFrame(T& data) { for (int i = 0; i < data.size(); ++i) { float input = data[i]; // If the input sample is below a small threshold, treat it as silence to save a little processing if (Math.abs(input) < 1e-6) // threshold value for silence { data[i] = 0.0f; continue; } // Normalize the input sample from its range [min, max] to [0, 1] so you can index the table float normalizedX = (input - (-1.0f)) / (1.0f - (-1.0f)); // Scale the normalized input to the lookup table index range float scaledIndex = normalizedX * (tableSize - 1); // Get the integer part of the index int index = static_cast<int>(scaledIndex); // Get fractional part for interpolation float frac = scaledIndex - index; // Interpolate between two points in the table float y0 = lookupTable[index]; float y1 = lookupTable[index + 1]; float output = y0 + frac * (y1 - y0); // Linear interpolation //If the output is very small set it to zero to prevent denormal numbers if (Math.abs(output) < 1e-10) output = 0.0f; data[i] = output; // Process with lookup table } } int handleModulation(double& value) { return 0; } void handleHiseEvent(HiseEvent& e) { // Add logic for handling events here } void setExternalData(const ExternalData& data, int index) { // Handle external data (if any) } // Parameter Functions ------------------------------------------------------------------------- template <int P> void setParameter(double v) { if (P == 0) { // Handle parameters } } void createParameters(ParameterDataList& data) { // Create parameters for the node { parameter::data p("MyParameter", { 0.0, 1.0 }); registerCallback<0>(p); p.setDefaultValue(0.5); data.add(std::move(p)); } } }; }
-
@Dan-Korneff Thanks.
Faust also has great interpolators.
https://faustlibraries.grame.fr/libs/interpolators/#interpolatorslib
-
If snex has access to juce, there are many excellent interpolators and there is a lookuptable class even I believe. I used it before with a good result.
I haven't tried accessing it in Snex though. -
@Dan-Korneff I tried to assign the code that you shared above to snex, but I get tons of errors.
Sorry for the inconvenience, do you have a chance to share the snex code directly?
template <int NV> struct LUTSNEX { SNEX_NODE(LUTSNEX); // Constants for the Lookup Table -------------------------------------------------------------- int tableSize = 200; // The size of the lookup table array float xMin = -1.0f; // Minimum input value (start of the input range) float xMax = 1.0f; // Maximum input value (end of the input range) float xRange = xMax - xMin; // Total range of input values // Lookup Table Data --------------------------------------------------------------------------- float lookupTable[tableSize] = { -0.356490f, -0.357427f, -0.358393f, -0.359388f, -0.360412f, -0.361464f, -0.362544f, -0.363653f, -0.364790f, -0.365954f, -0.367146f, -0.368366f, -0.369613f, -0.370887f, -0.372188f, -0.373515f, -0.374870f, -0.376251f, -0.377658f, -0.379091f, -0.380551f, -0.382031f, -0.383487f, -0.384854f, -0.386069f, -0.387067f, -0.387784f, -0.388167f, -0.388236f, -0.388037f, -0.387613f, -0.387010f, -0.386272f, -0.385446f, -0.384574f, -0.383703f, -0.382877f, -0.382142f, -0.381541f, -0.381120f, -0.380925f, -0.380999f, -0.381387f, -0.382135f, -0.383288f, -0.384889f, -0.386944f, -0.389391f, -0.392161f, -0.395186f, -0.398397f, -0.401724f, -0.405101f, -0.408457f, -0.411725f, -0.414835f, -0.417719f, -0.420308f, -0.422534f, -0.424328f, -0.425621f, -0.426345f, -0.426464f, -0.425989f, -0.424939f, -0.423329f, -0.421179f, -0.418503f, -0.415321f, -0.411648f, -0.407502f, -0.402900f, -0.397859f, -0.392396f, -0.386529f, -0.380274f, -0.373649f, -0.366634f, -0.359082f, -0.350815f, -0.341658f, -0.331433f, -0.319963f, -0.307071f, -0.292583f, -0.276464f, -0.258907f, -0.240127f, -0.220341f, -0.199765f, -0.178613f, -0.157102f, -0.135447f, -0.113863f, -0.092567f, -0.071774f, -0.051659f, -0.032214f, -0.013375f, 0.004921f, 0.022736f, 0.040134f, 0.057177f, 0.073928f, 0.090451f, 0.106808f, 0.123062f, 0.139276f, 0.155513f, 0.171836f, 0.188308f, 0.204992f, 0.221950f, 0.239246f, 0.256943f, 0.275078f, 0.293520f, 0.312062f, 0.330498f, 0.348620f, 0.366224f, 0.383101f, 0.399047f, 0.413853f, 0.427315f, 0.439226f, 0.449378f, 0.457566f, 0.463622f, 0.467645f, 0.469852f, 0.470458f, 0.469678f, 0.467729f, 0.464826f, 0.461186f, 0.457023f, 0.452555f, 0.447995f, 0.443562f, 0.439469f, 0.435933f, 0.433164f, 0.431234f, 0.430080f, 0.429634f, 0.429825f, 0.430586f, 0.431847f, 0.433540f, 0.435594f, 0.437942f, 0.440514f, 0.443241f, 0.446055f, 0.448886f, 0.451665f, 0.454324f, 0.456793f, 0.459003f, 0.460886f, 0.462372f, 0.463417f, 0.464063f, 0.464372f, 0.464405f, 0.464224f, 0.463891f, 0.463468f, 0.463016f, 0.462596f, 0.462272f, 0.462104f, 0.462155f, 0.462484f, 0.463117f, 0.464024f, 0.465173f, 0.466533f, 0.468071f, 0.469755f, 0.471553f, 0.473432f, 0.475361f, 0.477308f, 0.479239f, 0.481124f, 0.482929f, 0.484623f, 0.486174f, 0.487549f, 0.488716f, 0.489644f, 0.490299f, 0.490650f, 0.490665f, 0.490311f, 0.489556f, 0.488369f, 0.486716f }; // Define the amount and types of external data slots you want to use int NumTables = 0; int NumSliderPacks = 0; int NumAudioFiles = 0; int NumFilters = 0; int NumDisplayBuffers = 0; // Initialise the processing specs here void prepare(PrepareSpecs ps) { } // Reset the processing pipeline here void reset() { } // Process the signal here template <typename ProcessDataType> void process(ProcessDataType& data) { for (int i = 0; i < data.size(); ++i) { float input = data[i]; // If the input sample is below a small threshold, treat it as silence to save a little processing if (Math.abs(input) < 1e-6) // threshold value for silence { data[i] = 0.0f; continue; } // Normalize the input sample from its range [min, max] to [0, 1] so you can index the table float normalizedX = (input - (-1.0f)) / (1.0f - (-1.0f)); // Scale the normalized input to the lookup table index range float scaledIndex = normalizedX * (tableSize - 1); // Get the integer part of the index int index = static_cast<int>(scaledIndex); // Get fractional part for interpolation float frac = scaledIndex - index; // Interpolate between two points in the table float y0 = lookupTable[index]; float y1 = lookupTable[index + 1]; float output = y0 + frac * (y1 - y0); // Linear interpolation //If the output is very small set it to zero to prevent denormal numbers if (Math.abs(output) < 1e-10) output = 0.0f; data[i] = output; // Process with lookup table } } // Process the signal as frame here template <int C> void processFrame(span<float, C>& data) { } // Process the MIDI events here void handleHiseEvent(HiseEvent& e) { } // Use this function to setup the external data void setExternalData(const ExternalData& d, int index) { } // Set the parameters here template <int P> void setParameter(double v) { } };
-
@JulesV post the errors.
-
@Dan-Korneff said in Using LUT on SNEX:
@JulesV post the errors.
I posted the code that I tried above
-
@JulesV but the code doesn't show me the errors you're getting.
-
@JulesV @Dan-Korneff The thing with SNEX is that the errors in the console show up in a lazy fashion... Everything gets on one line, and often line numbers aren't showing anything but the last line number of the scripting window.
I tend to compile at every new line I write so I know when and where I introduced a mistake
-
@Dan-Korneff said in Using LUT on SNEX:
@JulesV but the code doesn't show me the errors you're getting.
Have you copy pasted my code above?
First of all, for
xRange
I getcan't assign static constant to a dynamic expression
error.This time when I move this variable to the
void process
function, I get theExpected initializer for non templated member
error for thelookupTable
array.@ustk I am new to snex, have you tried the code above?
-
@JulesV said in Using LUT on SNEX:
First of all, for xRange I get can't assign static constant to a dynamic expression error.
Probably here:
float xRange = xMax - xMin;
This shouldn't be the case as the dependent variables are not
static const
I get this all the time too, forcing to initialise using literals... @Christoph-Hart ? -
@Christoph-Hart Can we ask you for a proper working example snippet for the use of lut in snex, which is asked in this topic?
-
Sorry for the late reply. I just realized that I'm using a 3rd party node for my LUT test.
Here's the full project you guys can take a look:
https://hub.korneffaudio.com/index.php/s/xPcEwQicPH63Fkd