Forum
    • Categories
    • Register
    • Login
    1. Home
    2. Chazrox
    3. Topics
    • Profile
    • Following 6
    • Followers 6
    • Topics 189
    • Posts 1,652
    • Groups 0

    Topics

    • ChazroxC

      // NEW : Online Button Builder for HISE! // LAF & PNG Filmstrip Exports // Feedback Welcome!

      Watching Ignoring Scheduled Pinned Locked Moved Scripting laf svg nuemorphic button designer online editor
      3
      4 Votes
      3 Posts
      63 Views
      ChazroxC

      @resonant Thanks bro! 🙏 ⚡

    • ChazroxC

      SVG -> base64 Batch conversion?

      Watching Ignoring Scheduled Pinned Locked Moved Scripting
      7
      0 Votes
      7 Posts
      195 Views
      ChazroxC

      @dannytaurus

      I tried to load a 'duo-tone' svg with Base64SVG and this is the result?

      Screenshot 2026-07-01 at 2.40.49 AM.png

      SVG file:

      Screenshot 2026-07-01 at 2.42.10 AM.png

      Am I doing something wrong or not understanding something?

    • ChazroxC

      Rotation around center of mass is weird.

      Watching Ignoring Scheduled Pinned Locked Moved Solved Scripting
      14
      0 Votes
      14 Posts
      789 Views
      ChazroxC

      StarKnobNoiseMaskLayerFixed.gif

      Heres the fix:

      MyKnobLaf.registerFunction("drawRotarySlider", function(g, obj) { var a = obj.area; var range = obj.max - obj.min; var stableSize = a[2] * (1.0 - 2.0 * 0.15); var ox = a[0] + (a[2] - stableSize) / 2; var oy = a[1] + (a[2] - stableSize) / 2; var cx = ox + stableSize / 2; var cy = oy + stableSize / 2; var sw = stableSize / 200.0; var startOffset = 2.5; var totalSweep = 2.0 * startOffset; var endOffset = -startOffset + totalSweep * (obj.value - obj.min) / range; var cStarBody3Top = 0xffFF0000; var cStarBody3Bot = 0xff00FBFF; var cStarBody3Outline = 0xfa000000; var starBody3Size = stableSize * 0.76; var starBody3X = cx - starBody3Size * 0.5; var starBody3Y = cy - starBody3Size * 0.5; var starBody3Static = Content.createPath(); starBody3Static.addStar([0.5, 0.5], 3, 0.13, 0.5, 0); starBody3Static.roundCorners(1); var starBody3StaticBounds = starBody3Static.getBounds(starBody3Size).translated(starBody3X, starBody3Y); var starBody3Star = Content.createPath(); starBody3Star.addStar([0.5, 0.5], 6, 0.05, 0.6, endOffset); starBody3Star.roundCorners(1); var starBody3RotBounds = starBody3Star.getBounds(starBody3Size).translated(starBody3X, starBody3Y); // PASS 1: gradient fill g.beginLayer(false); g.setGradientFill([cStarBody3Top, cx, starBody3Y, cStarBody3Bot, cx, starBody3Y + starBody3Size, false]); g.fillPath(starBody3Star, starBody3RotBounds); g.endLayer(); // PASS 2: noise — use full obj.area so noise fills behind mask cleanly g.beginLayer(false); g.applyMask(starBody3Star, starBody3RotBounds, false); g.rotate(endOffset, [cx, cy]); g.addNoise({"alpha": 0.3, "monochromatic": true, "area": [a[0], a[1], a[2] * 2, a[3] * 2]}); g.rotate(-endOffset, [cx, cy]); g.endLayer(); // PASS 3: outline g.beginLayer(false); g.setColour(cStarBody3Outline); g.drawPath(starBody3Star, starBody3RotBounds, 3.06 * sw); g.endLayer(); });
    • ChazroxC

      Ellipse Masking // Mask makes shape dark.

      Watching Ignoring Scheduled Pinned Locked Moved Unsolved Scripting
      13
      0 Votes
      13 Posts
      783 Views
      ChazroxC

      Update: I bowed out gracefully.....for now lol

    • ChazroxC

      UPDATE // NEW: Online Knob Builder for HISE!! // Added: InnerShadows, Angled DropShadows, GradientOutlines.

      Watching Ignoring Scheduled Pinned Locked Moved Scripting laf knobs knob designer scalable knob online editor
      79
      12 Votes
      79 Posts
      3k Views
      ChazroxC

      @digi I can add this. 'Gradient Rotation offset'. I'll push this when I get home tonight.

    • ChazroxC

      Drawing gradient along a path? Thermometer style gradient?

      Watching Ignoring Scheduled Pinned Locked Moved Scripting
      17
      0 Votes
      17 Posts
      1k Views
      dannytaurusD

      @Chazrox Never used them, sorry.

    • ChazroxC

      C++ Global Cables // How to add multiple cables to an existing compiled network.

      Watching Ignoring Scheduled Pinned Locked Moved Scripting
      2
      0 Votes
      2 Posts
      202 Views
      griffinboyG

      @Chazrox

      I don't have a "clean" example.
      This is old code too, so not a good example of good c++ node practices or anything like that.

      But here is a c++ node with a global cable(s) set up.

      I've had no problems before, with updating existing c++ headers when adding more global cables.

      If you make sure that the generated global cable code is up to date.
      When you create more cables, you need to re-generate the global cable c++ code in Hise and update those parts in the c++

      This generated stuff needs to be kept up to date with the cable names and IDs in your Hise project:

      enum class GlobalCables { grainpos = 0 }; using cable_manager_t = routing::global_cable_cpp_manager<SN_GLOBAL_CABLE(94428153)>;

      ^ Here, only one global cable exists, however when you add more global cables to your Hise project, this code will need regenerating / updating with the new names and IDs of the cables in your Hise project.

      C++ node example (using one global cable):

      // FILE: Griffin_GrainOsc.h /* Granular OSC node: per-voice state & note-reactive pitch. Each voice owns a Granulator instance via snex::PolyData so reset/prepare are scoped to the active voice. Pitch maps so that MIDI note 60 plays the sample at its original pitch / speed */ #pragma once #include <JuceHeader.h> #include <array> #include <vector> #include <deque> #include <cmath> #include <atomic> #include "src/GriffinGrainOsc/GGO_GranularEngine.h" namespace project { using namespace juce; using namespace hise; using namespace scriptnode; enum ParamID { kGrainSizeMs, kDensityHz, kMainPos, kSpray, kPitchSt, kRandPitch, kRandSize, kStereoSpread, kReverseChance, kEnvMode, kMaxGrains, kNumParams }; enum class GlobalCables { grainpos = 0 }; using cable_manager_t = routing::global_cable_cpp_manager<SN_GLOBAL_CABLE(94428153)>; template<int NV> struct Griffin_GrainOsc : public data::base, public cable_manager_t { SNEX_NODE(Griffin_GrainOsc); struct MetadataClass { SN_NODE_ID("Griffin_GrainOsc"); }; 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; } static constexpr int NumTables = 0, NumSliderPacks = 0, NumAudioFiles = 1, NumFilters = 0, NumDisplayBuffers = 0; struct Voice { ggrain::Granulator<float> gran; uint32_t lastGrainSm{ 0 }; double lastDensityHz{ -1.0 }; int note{ 60 }; double sr{ 44100.0 }; void prepare(double sampleRate) { sr = sampleRate; gran.prepare(sr); lastGrainSm = 0; lastDensityHz = -1.0; } void reset() { gran.prepare(sr); // keeps grains cleared, parameters intact lastGrainSm = 0; lastDensityHz = -1.0; } void setSample(const float* mono, uint32_t num, double fileSr) { gran.loadSample(mono, num, fileSr); } }; template<typename PD> void process(PD& d) { auto& fix = d.template as<snex::Types::ProcessData<2>>(); auto blk = fix.toAudioBlock(); float* L = blk.getChannelPointer(0); float* R = blk.getChannelPointer(1); auto& v = voices.get(); v.gran.process(L, R, d.getNumSamples()); flushSpawnEvents(); } void prepare(snex::Types::PrepareSpecs s) { sr = s.sampleRate; voices.prepare(s); for (auto& v : voices) { v.prepare(sr); v.gran.setSpawnCallback(&Griffin_GrainOsc::onSpawnThunk, this); v.gran.setSpawnInfoCallback(&Griffin_GrainOsc::onSpawnInfoThunk, this); } // Leave existing param cache alone in runtime use; these are only defaults for first-time init. params[kGrainSizeMs] = (params[kGrainSizeMs] == 0.0 ? 100.0 : params[kGrainSizeMs]); params[kDensityHz] = (params[kDensityHz] == 0.0 ? 5.0 : params[kDensityHz]); params[kMainPos] = (params[kMainPos] == 0.0 ? 0.5 : params[kMainPos]); params[kSpray] = (params[kSpray] == 0.0 ? 0.0 : params[kSpray]); params[kPitchSt] = params[kPitchSt]; // keep params[kRandPitch] = params[kRandPitch]; params[kRandSize] = params[kRandSize]; params[kStereoSpread] = params[kStereoSpread]; params[kReverseChance] = params[kReverseChance]; params[kEnvMode] = (params[kEnvMode] == 0.0 ? 2.0 : params[kEnvMode]); for (auto& v : voices) params[kMaxGrains] = (double)v.gran.capacity(); applyParamsAll(); qCount.store(0, std::memory_order_relaxed); seq.store(0, std::memory_order_relaxed); } template<int P> void setParameter(double v) { static_assert(P < kNumParams); params[P] = v; for (auto& voice : voices) applyParamsForVoice(voice); } void createParameters(ParameterDataList& data) { using PD = parameter::data; PD pSize("GrainSizeMs", { 1.0, 2000.0, 0.01 }); pSize.setDefaultValue(100.0); pSize.setSkewForCentre(100.0); registerCallback<kGrainSizeMs>(pSize); data.add(pSize); PD pDen("DensityHz", { 0.1, 200.0, 0.0001 }); pDen.setDefaultValue(5.0); pDen.setSkewForCentre(10.0); registerCallback<kDensityHz>(pDen); data.add(pDen); PD pPos("Position", { 0.0, 1.0, 0.0001 }); pPos.setDefaultValue(0.0); registerCallback<kMainPos>(pPos); data.add(pPos); PD pSpr("Spray", { 0.0, 1.0, 0.0 }); pSpr.setDefaultValue(0.0); pSpr.setSkewForCentre(0.2); registerCallback<kSpray>(pSpr); data.add(pSpr); PD pPst("PitchSt", { -36.0, 36.0, 0.001 }); pPst.setDefaultValue(0.0); registerCallback<kPitchSt>(pPst); data.add(pPst); PD pRP("RandPitch", { 0.0, 1.0, 0.0 }); pRP.setDefaultValue(0.0); pRP.setSkewForCentre(0.08); registerCallback<kRandPitch>(pRP); data.add(pRP); PD pRS("RandSize", { 0.0, 1.0, 0.0001 }); pRS.setDefaultValue(0.0); pRS.setSkewForCentre(0.4); registerCallback<kRandSize>(pRS); data.add(pRS); PD pSpread("RandPan", { 0.0, 1.0, 0.0001 }); pSpread.setDefaultValue(0.0); pSpread.setSkewForCentre(0.35); registerCallback<kStereoSpread>(pSpread); data.add(pSpread); PD pRev("ReverseChance", { 0.0, 1.0, 0.0001 }); pRev.setDefaultValue(0.0); pRev.setSkewForCentre(0.4); registerCallback<kReverseChance>(pRev); data.add(pRev); PD pEnv("EnvelopeShape", { 0.0, 2.0, 1.0 }); pEnv.setDefaultValue(2.0); registerCallback<kEnvMode>(pEnv); data.add(pEnv); PD pCap("MaxVoiceGrains", { 1.0, (double)128.0, 1.0 }); pCap.setDefaultValue((double)128.0); registerCallback<kMaxGrains>(pCap); data.add(pCap); } /* Safe sample load: - Push newest buffer. - Point all voices at newest buffer (Granulator snapshots pointer/size). - Compact pool keeping newest and any buffers still used by active grains. */ void setExternalData(const snex::ExternalData& ed, int) override { using DT = snex::ExternalData::DataType; if (ed.dataType != DT::AudioFile) return; if (ed.isXYZ()) return; if (ed.isEmpty()) return; if (ed.numChannels <= 0 || ed.numChannels > 2) return; if (ed.numSamples <= 0 || ed.sampleRate <= 0.0) return; auto buf = ed.toAudioSampleBuffer(); const int nc = buf.getNumChannels(); const int ns = buf.getNumSamples(); if (ns <= 0 || (nc != 1 && nc != 2)) return; const double maxSec = 600.0; const int cap = juce::jmin(ns, (int)juce::roundToInt(ed.sampleRate * maxSec)); SampleBuf newest; newest.data.resize((size_t)cap); if (nc == 1) { const float* s0 = buf.getReadPointer(0); for (int i = 0; i < cap; ++i) { float x = s0[i]; if (!std::isfinite(x)) x = 0.0f; newest.data[(size_t)i] = juce::jlimit(-1.0f, 1.0f, x); } } else { const float* L = buf.getReadPointer(0); const float* R = buf.getReadPointer(1); for (int i = 0; i < cap; ++i) { float x = 0.5f * (L[i] + R[i]); if (!std::isfinite(x)) x = 0.0f; newest.data[(size_t)i] = juce::jlimit(-1.0f, 1.0f, x); } } newest.srcRate = ed.sampleRate; pool.push_back(std::move(newest)); const size_t newestIdx = pool.size() - 1; const float* newestPtr = pool[newestIdx].data.data(); const uint32_t newestSz = (uint32_t)pool[newestIdx].data.size(); const double newestSR = pool[newestIdx].srcRate; for (auto& v : voices) v.setSample(newestPtr, newestSz, newestSR); if (pool.size() <= 1) return; size_t write = 0; for (size_t read = 0; read < pool.size(); ++read) { const bool keepNewest = (read == newestIdx); bool keep = keepNewest; if (!keepNewest) { const float* p = pool[read].data.data(); for (auto& v : voices) { if (v.gran.isSamplePointerInUse(p)) { keep = true; break; } } } if (keep) { if (write != read) pool[write] = std::move(pool[read]); ++write; } } pool.resize(write); } void reset() { for (auto& v : voices) { v.reset(); // clear grains; keep parameters/seeds/buffers applyParamsForVoice(v); } qCount.store(0, std::memory_order_relaxed); } void handleHiseEvent(HiseEvent& e) { if (e.isNoteOn()) { auto& v = voices.get(); v.gran.flush(true); v.note = e.getNoteNumberIncludingTransposeAmount(); applyParamsForVoice(v); } } SN_EMPTY_PROCESS_FRAME; void connectToRuntimeTarget(bool addConnection, const runtime_target::connection& c) override { cable_manager_t::connectToRuntimeTarget(addConnection, c); } private: // GUI spawn-event sender juce::Array<juce::var> packed; void flushSpawnEvents() { const int N = qCount.exchange(0, std::memory_order_acq_rel); if (N <= 0) { packed.clearQuick(); return; } packed.clearQuick(); packed.ensureStorageAllocated(N * 3); for (int i = 0; i < N; ++i) { packed.add(juce::var((double)qP0[(size_t)i])); packed.add(juce::var((double)qVel[(size_t)i])); packed.add(juce::var((double)qDurMs[(size_t)i])); } this->sendDataToGlobalCable<GlobalCables::grainpos>(juce::var(packed)); } static void onSpawnThunk(void*, float) {} static void onSpawnInfoThunk(void* user, float p0, float v01ps, float durMs) { auto* self = static_cast<Griffin_GrainOsc*>(user); if (!self) return; const int idx = self->qCount.load(std::memory_order_relaxed); if ((unsigned)idx >= (unsigned)kQueueCap) return; self->qP0[(size_t)idx] = p0; self->qVel[(size_t)idx] = v01ps; self->qDurMs[(size_t)idx] = durMs; self->qCount.store(idx + 1, std::memory_order_release); } void applyParamsAll() { for (auto& v : voices) applyParamsForVoice(v); } void applyParamsForVoice(Voice& v) { const double grainMs = juce::jlimit(1.0, 2000.0, params[kGrainSizeMs]); const double densityHz = juce::jlimit(0.1, 200.0, params[kDensityHz]); uint32_t grainSm = (uint32_t)juce::roundToInt((grainMs * 0.001) * v.sr); if (grainSm == 0) grainSm = 1; const bool lenChanged = (grainSm != v.lastGrainSm); const bool denChanged = (std::abs(densityHz - v.lastDensityHz) > 1e-12); if (lenChanged || denChanged) { v.gran.setParameters(grainSm, densityHz, 0.0); v.lastGrainSm = grainSm; v.lastDensityHz = densityHz; } ggrain::SpawnParams sp{}; sp.mainPos01 = juce::jlimit(0.0, 1.0, params[kMainPos]); sp.spray01 = juce::jlimit(0.0, 1.0, params[kSpray]); sp.sprayMode = ggrain::SprayMode::Gaussian; sp.baseLenSm = grainSm; sp.sizeRand01 = juce::jlimit(0.0, 1.0, params[kRandSize]); // Honor requested pitch exactly (no limiting). UI control is still clamped, but note+UI sum is not. const double uiPitchSt = juce::jlimit(-36.0, 36.0, params[kPitchSt]); const double noteSemis = (double)v.note - 60.0; sp.pitchSemitones = uiPitchSt + noteSemis; sp.pitchRand01 = juce::jlimit(0.0, 1.0, params[kRandPitch]); sp.reverseChance01 = juce::jlimit(0.0, 1.0, params[kReverseChance]); sp.stereoSpread01 = juce::jlimit(0.0, 1.0, params[kStereoSpread]); const int envIdx = (int)juce::jlimit(0.0, 2.0, params[kEnvMode]); sp.envMode = (envIdx == 0 ? ggrain::EnvelopeMode::RectRaisedCos : envIdx == 1 ? ggrain::EnvelopeMode::Triangle : ggrain::EnvelopeMode::Hanning); v.gran.setSpawnParams(sp); const size_t cap = v.gran.capacity(); const size_t want = (size_t)juce::roundToInt(juce::jlimit(1.0, (double)cap, params[kMaxGrains])); v.gran.setMaxActiveGrains(want); } struct SampleBuf { std::vector<float> data; double srcRate{ 44100.0 }; }; static constexpr int kQueueCap = 512; double sr{ 44100.0 }; std::array<double, kNumParams> params{}; snex::PolyData<Voice, NV> voices; std::vector<SampleBuf> pool; std::array<float, kQueueCap> qP0{}; std::array<float, kQueueCap> qVel{}; std::array<float, kQueueCap> qDurMs{}; std::atomic<int> qCount{ 0 }; std::atomic<int> seq{ 0 }; }; }
    • ChazroxC

      HISE Update broke my project.

      Watching Ignoring Scheduled Pinned Locked Moved Scripting
      29
      0 Votes
      29 Posts
      2k Views
      David HealeyD

      @Chazrox said in HISE Update broke my project.:

      If its not an xml problem whats my next move?

      If it was me I'd crack open a debugger and see what it says, not a simple thing to explain how to here though.

    • ChazroxC

      Trading DSP's!

      Watching Ignoring Scheduled Pinned Locked Moved Scripting
      10
      1 Votes
      10 Posts
      822 Views
      C

      @Chazrox Have got a Glitch FX and a Granular Pitch Delay. Would be interested in the pitch and varispeed!

    • ChazroxC

      UNDO - Swap Scriptnode FX w/ Dlls

      Watching Ignoring Scheduled Pinned Locked Moved Unsolved ScriptNode
      18
      0 Votes
      18 Posts
      403 Views
      ChazroxC

      @ustk Ok I think im understanding. Thank you.

    • ChazroxC

      How do I port DspNetworks ---> NewProject file ?

      Watching Ignoring Scheduled Pinned Locked Moved Scripting
      8
      0 Votes
      8 Posts
      543 Views
      ChazroxC

      @HISEnberg @David-Healey Yup that works! I get it now. I've been compiling like a mad man lol

    • ChazroxC

      Dsp network wont compile: // <--Changed to more relevant title :)

      Watching Ignoring Scheduled Pinned Locked Moved Solved Scripting
      69
      0 Votes
      69 Posts
      4k Views
      ChazroxC

      FIXED!!!!!! 😭 😭

      Screenshot 2026-06-05 at 7.22.38 PM.png

      @David-Healey @HISEnberg @dannytaurus OMG! A Year of trying and it was a stale template file....I wanna cry. lol

      Finally made it to this window:

      Screenshot 2026-06-05 at 7.25.10 PM.png

      and compiled dll successfully !

      Screenshot 2026-06-05 at 7.37.24 PM.png

    • ChazroxC

      "Error at node: chain" while 'compiling network to dll'

      Watching Ignoring Scheduled Pinned Locked Moved Unsolved Scripting
      16
      0 Votes
      16 Posts
      948 Views
      HISEnbergH

      I'm looking for documents and examples to guide you and I am seeing this is rather poorly documented.

      Basically DspNetworks folder works like this:

      DspNetworks/Binaries: The compiled DLL. When you compile networks to .dll, HISE is launching and creating a mini-project of just your FX networks, so it contains a .jucer, XCode or VisualStudio file, etc. DLL (Dynamic Link Library) is, to put it crudely, a pre-written and formatted library that contains the DSP code which HISE can load at runtime (for example, load into the HardcodedMasterFx). You can simply delete the entire Binaries folder before compile to DLL for a fresh start (in fact it is a good idea). More info here: https://docs.hise.dev/scriptnode/manual/third_party.html

      DspNetworks/CodeLibrary: I don't look here much, but it's usually where a lot of the faust and snex networks are saved to.

      DspNetworks/Networks: Where scriptnode networks are saved as .xml. So you can actually look at these in a code editor and see the same structure flow and module settings (it is fairly human readable). This is what is saved and recalled when you are launching networks (it's very similar to how a User Preset works).

      DspNetworks/ThirdParty: Mainly for C++ files if you are working that way. I think Snex headers are stashed here as well (I can't remember). You'll also notice HISE will autogenerate headers depending on what you are using, example for Faust.

      AdditionalSourceCode/nodes: This is also important. When you go to compile networks you see the menu below. Basically it is autogenerating some headers that are stashed here for when you are ready to compile the entire project. They help link the compiler to the necessary DSP files. You don't really ever need to bother with this folder, but for a completely fresh build, you can just delete the "nodes" folder before compiling the networks to DLL.

      Screenshot 2026-06-04 at 6.58.44 AM.png

    • ChazroxC

      Stupid Quotation marks behavior....

      Watching Ignoring Scheduled Pinned Locked Moved Solved Scripting
      14
      0 Votes
      14 Posts
      887 Views
      ChazroxC

      @Christoph-Hart I can breathe again....and move much faster now lol

    • ChazroxC

      Get Panel Attributes - Colours

      Watching Ignoring Scheduled Pinned Locked Moved Solved Scripting
      11
      0 Votes
      11 Posts
      557 Views
      ustkU

      @David-Healey There might be a bad parsing at some point. Without really knowing, the hex might be first parsed as string by the property editor...

    • ChazroxC

      Script Oscilloscope Buffer Size

      Watching Ignoring Scheduled Pinned Locked Moved Scripting
      5
      0 Votes
      5 Posts
      432 Views
      ChazroxC

      @ustk ahh. makes sense. Thank you.

    • ChazroxC

      Can we detect DAW marker points?

      Watching Ignoring Scheduled Pinned Locked Moved Scripting
      5
      0 Votes
      5 Posts
      307 Views
      ChazroxC

      @Lindon Still a good read either way. Good stuff to know. 🤛

    • ChazroxC

      Set Label Text on Preset Load?

      Watching Ignoring Scheduled Pinned Locked Moved Scripting
      3
      0 Votes
      3 Posts
      275 Views
      ChazroxC

      @David-Healey Thanks! I ended up figuring it out from an old post you advised on as well. lol. Attached the callback to a slider with 'save in preset' loaded that triggers the callback on preset load.