• Full Expansions Included Scripts

    Scripting
    12
    0 Votes
    12 Posts
    30 Views
    S

    @David-Healey The Problem was that I was including the same Expansions.js in the actual Expansion! Ive commented that and deleted the file and is working in the exported Plugin!

  • 1 Votes
    3 Posts
    20 Views
    dannytaurusD

    @David-Healey I doubt it. Once you start notarising, I reckon you'll never stop.

  • Custom controls

    General Questions
    27
    0 Votes
    27 Posts
    70 Views
    MorphoiceM

    @David-Healey I rewired a test slider in my plugin as a panel-as-parameter exactly like you did in your example, no change in Cubase. I'm attempting to patch HISE to have that handle click gated

  • 0 Votes
    12 Posts
    127 Views
    B

    @David-Healey Thank you, kind sir.

  • 0 Votes
    11 Posts
    41 Views
    Y

    @Oli-Ullmann Ok,

    Thank you 🙏

  • Testers Needed for Rhapsody v3

    General Questions
    36
    1 Votes
    36 Posts
    998 Views
    David HealeyD

    @jeffd Thanks for confirming.

  • Bug: Wavetable only imports to left channel

    Bug Reports
    10
    0 Votes
    10 Posts
    76 Views
    dannytaurusD

    @paper_lung Gotcha. Not too far behind then. Still worth getting up to date though 👍

  • 1 Votes
    3 Posts
    181 Views
    B

    @VybeCodeDSP StripKit looks really nice!

    It seems you only support the Windows platform?
    If so, are you planning to support MacOS?
    If so, let me know if you need a beta tester!

  • waveform: draw loop position/crossfade

    General Questions
    2
    0 Votes
    2 Posts
    41 Views
  • Which version of faust works fine for HISE?

    Faust Development
    2
    0 Votes
    2 Posts
    72 Views
    David HealeyD

    @Sawatakashi said in Which version of faust works fine for HISE?:

    it crashed after i loaded a faust scriptnode.

    A blank node or are you copying in a script?

  • 0 Votes
    3 Posts
    93 Views
    griffinboyG

    @Phelan-Kane

    Here's a real life example of c++ modslots.

    It's not minimal i'm afraid but it shows it in use.
    If you'd like to see the minimal example, it's just as @ustk said, have a look at this post:
    https://forum.hise.audio/topic/14270/how-do-you-set-up-external-modulation-slots-c

    // ==============================| Griffin Poly EQ Filter |=================================== // // File: Griffin_EQFilter_Poly.h // Node: Griffin_EQFilter_Poly // Package: Griffin DSP Essentials for HISE // Author: Griffinboy // HISE Forum: https://forum.hise.audio/user/griffinboy // Copyright: Copyright (c) 2026 Griffinboy // // Description: // Minimum-phase EQ filter with per-voice state and frame processing. // Designed for sample-accurate modulation in synthesis contexts. // Uses more CPU than the block-rate Griffin_EQFilter. // // Has Mod slots for frequency, Q, and gain. // // License: // GNU General Public License v3.0 or later (GPL-3.0-or-later). // // This file is part of Griffin DSP Essentials for HISE. // // This program is free software: you can redistribute it and/or modify it under the // terms of the GNU General Public License as published by the Free Software Foundation, // either version 3 of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A // PARTICULAR PURPOSE. See the GNU General Public License for more details. // // You should have received a copy of the GNU General Public License along with this // program. If not, see <https://www.gnu.org/licenses/>. // // ================================================================================================ #pragma once #include <algorithm> #include <cmath> #include <JuceHeader.h> #include "src/griffinboy/modules/essentials/eq_filter/eq_filter.h" namespace project { using namespace juce; using namespace hise; using namespace scriptnode; template <int NV> struct Griffin_EQFilter_Poly: public data::filter_node_base { using VoiceState = griffin::modules::essentials::eq_filter::EQFilterFrameProcessor; using PlotModel = griffin::modules::essentials::eq_filter::EQPlotModel; using Defaults = griffin::modules::essentials::eq_filter::EQFilterDefaults; PolyData<VoiceState, NV> voices; PlotModel plotModel; SimpleReadWriteLock topologyLock; double plotSampleRate = 44100.0; SNEX_NODE(Griffin_EQFilter_Poly); struct MetadataClass { SN_NODE_ID("Griffin_EQFilter_Poly"); }; static constexpr bool isModNode() { return false; }; static constexpr bool isPolyphonic() { return NV > 1; }; static constexpr bool hasTail() { return true; }; static constexpr bool isSuspendedOnSilence() { return true; }; static constexpr int getFixChannelAmount() { return 2; }; static constexpr int NumTables = 0; static constexpr int NumSliderPacks = 0; static constexpr int NumAudioFiles = 0; static constexpr int NumFilters = 1; static constexpr int NumDisplayBuffers = 0; void prepare(PrepareSpecs specs) { SimpleReadWriteLock::ScopedWriteLock sl(topologyLock); voices.prepare(specs); for (auto& voice : voices) voice.prepare(specs.sampleRate, specs.blockSize); plotModel.prepare(specs.sampleRate); plotSampleRate = specs.sampleRate > 0.0 ? specs.sampleRate : 44100.0; if (auto fd = dynamic_cast<FilterDataObject*>(this->externalData.obj)) fd->setSampleRate(plotSampleRate); sendCoefficientUpdateMessage(); voiceManager.prepare(specs); voiceManager.setActive(1.0); } void reset() { SimpleReadWriteLock::ScopedWriteLock sl(topologyLock); for (auto& voice : voices) voice.reset(); voiceManager.reset(); } void handleHiseEvent(HiseEvent& e) { voiceManager.handleHiseEvent(e); } template <typename T> void process(T& data) { if (auto sl = SimpleReadWriteLock::ScopedTryReadLock(topologyLock)) { static constexpr int NumChannels = getFixChannelAmount(); auto& fixData = data.template as<ProcessData<NumChannels>>(); auto& voice = voices.get(); auto fd = fixData.toFrameData(); while (fd.next()) voice.processFrame(fd.toSpan()); voiceManager.process(data); } } template <typename T> void processFrame(T& data) { if (auto sl = SimpleReadWriteLock::ScopedTryReadLock(topologyLock)) voices.get().processFrame(data); } int handleModulation(double& value) { ignoreUnused(value); return 0; } double getPlotValue(int getMagnitude, double freqNorm) override { if (getMagnitude == 0) return 0.0; const auto frequency = std::clamp(freqNorm, 0.0, 0.5) * plotSampleRate; return plotModel.getMagnitudeAtFrequency(frequency); } void setExternalData(const ExternalData& data, int index) { data::filter_node_base::setExternalData(data, index); ignoreUnused(index); if (auto fd = dynamic_cast<FilterDataObject*>(data.obj)) fd->setSampleRate(plotSampleRate); sendCoefficientUpdateMessage(); } void createExternalModulationInfo(OpaqueNode::ModulationProperties& info) { modulation::ParameterProperties::ConnectionList list; auto addParameterSlot = [&list](int parameterIndex) { modulation::ConnectionInfo slot; slot.connectedParameterIndex = parameterIndex; slot.modColour = HiseModulationColours::ColourId::FX; slot.connectionMode = modulation::ConnectionMode::Parameter; slot.modulationMode = modulation::ParameterMode::ScaleAdd; list.push_back(slot); }; addParameterSlot(2); addParameterSlot(3); addParameterSlot(4); info.fromConnectionList(list); info.setModulationBlockSize(Defaults::modulationBlockSize); } template <int P> void setParameter(double v) { if constexpr (P == 0) { SimpleReadWriteLock::ScopedWriteLock sl(topologyLock); const auto nextShape = (int)std::round(v); applyToVoices( [nextShape](VoiceState& filter) { filter.setType(nextShape); }); updatePlotFromFirstVoice( [this, nextShape] { plotModel.setType(nextShape); }); } else if constexpr (P == 1) { SimpleReadWriteLock::ScopedWriteLock sl(topologyLock); const auto nextSlope = (int)std::round(v); applyToVoices( [nextSlope](VoiceState& filter) { filter.setSlopeMode(nextSlope); }); updatePlotFromFirstVoice( [this, nextSlope] { plotModel.setSlopeMode(nextSlope); }); } else if constexpr (P == 2) { const auto value = (float)v; applyToVoices( [value](VoiceState& filter) { filter.setFrequencyHz(value); }); updatePlotFromFirstVoice( [this, value] { plotModel.setFrequencyHz(value); }); } else if constexpr (P == 3) { const auto value = (float)v; applyToVoices( [value](VoiceState& filter) { filter.setQ(value); }); updatePlotFromFirstVoice( [this, value] { plotModel.setQ(value); }); } else if constexpr (P == 4) { const auto value = (float)v; applyToVoices( [value](VoiceState& filter) { filter.setGainDb(value); }); updatePlotFromFirstVoice( [this, value] { plotModel.setGainDb(value); }); } } void createParameters(ParameterDataList& data) { { parameter::data p("Shape", { 0.0, 6.0, 1.0 }); StringArray names; addTypeLabels(names); p.setParameterValueNames(names); registerCallback<0>(p); p.setDefaultValue((double)Defaults::type); data.add(std::move(p)); } { parameter::data p("Slope", { 0.0, 3.0, 1.0 }); StringArray names; addSlopeLabels(names); p.setParameterValueNames(names); registerCallback<1>(p); p.setDefaultValue((double)Defaults::slopeMode); data.add(std::move(p)); } { parameter::data p("Frequency", { 20.0, 20000.0, 0.01 }); p.setSkewForCentre(1000.0); p.info.textConverter = parameter::pod::TextValueConverters::Frequency; registerCallback<2>(p); p.setDefaultValue(Defaults::frequencyHz); data.add(std::move(p)); } { parameter::data p("Q", { 0.025, 25.0, 0.001 }); p.setSkewForCentre(0.70710678); registerCallback<3>(p); p.setDefaultValue(Defaults::q); data.add(std::move(p)); } { parameter::data p("Gain", { -30.0, 30.0, 0.01 }); p.info.textConverter = parameter::pod::TextValueConverters::Decibel; registerCallback<4>(p); p.setDefaultValue(Defaults::gainDb); data.add(std::move(p)); } } private: static constexpr int getNumTypes() noexcept { return griffin::modules::essentials::eq_filter::EQFilterDesign::getNumTypes(); } template <typename Function> void applyToVoices(Function&& function) { // PolyData iteration follows HISE's poly callback. // Each active voice receives the parameter update in its own DSP state. for (auto& voice : voices) function(voice); } template <typename Function> void updatePlotFromFirstVoice(Function&& function) { // The plot is shared UI state. The first HISE voice owns graph updates // so voices do not compete for the displayed response. if (! voices.isVoiceRenderingActive() || voices.isFirst()) { function(); sendCoefficientUpdateMessage(); } } static void addTypeLabels(StringArray& names) { names.add("Lowpass"); names.add("Highpass"); names.add("Bandpass"); names.add("Notch"); names.add("Bell"); names.add("Low Shelf"); names.add("High Shelf"); } static void addSlopeLabels(StringArray& names) { names.add("12 dB/oct"); names.add("24 dB/oct"); names.add("48 dB/oct"); names.add("96 dB/oct"); } envelope::silent_killer<NV> voiceManager; }; } // namespace project
  • Animated modulation

    General Questions
    23
    0 Votes
    23 Posts
    407 Views
    ustkU

    @dannytaurus Yeah, keeping the colours tidy in your code is easier in the end. Then you can set the component colours from script when needed and everything updates automatically if you adjust something instead of copy/paste in all components...

    I tend to to everything I can in paint routines, the less components in the tree, the happier I am!
    That being said... In order to reduce CPU load, I still tend to keep fixed drawing (bg, mask, etc...) in separate panels so the LAF function job is only constrained to what is really necessary. I also keep all the math constants externally, unlike the example...

    Other issue with the "multiple panel masking technique" is that when you want to move it, it can be very annoying, unless adding them all in an holder panel, which is one more component... 😬

  • Trading DSP's!

    Scripting
    10
    1 Votes
    10 Posts
    222 Views
    C

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

  • The Legato between samplers

    General Questions
    6
    0 Votes
    6 Posts
    171 Views
    David HealeyD

    @Felix-W Break it down. Make a minimal project with one sampler where notes only trigger during legato transitions. Once you get that working you can start to incorporate it into your project.

  • Get, post API Hise language.

    General Questions
    7
    0 Votes
    7 Posts
    105 Views
    Y

    @David-Healey Ok,

    Is it possible to discuss in private?

  • Stop pruning default values from XML?

    General Questions
    4
    0 Votes
    4 Posts
    156 Views
    David HealeyD

    @dannytaurus said in Stop pruning default values from XML?:

    because I'm setting some values in script that happen to be default values.

    Hmm this might be the source of an issue I was having too, I might try it.

  • One shared Script Voice Start Modulator for many Samplers?

    Scripting
    5
    0 Votes
    5 Posts
    150 Views
    observantsoundO

    @David-Healey Yes the Global Modulator Container worked beautifully for this.
    Thanks to your video I've now also understood the global modulator container better.

    Regarding the body + release in one sampler:
    That's what I've tried first, but it's bugged when using together with loop regions.
    It's what I described in this earlier post you commented on:
    https://forum.hise.audio/topic/14799/loud-click-artifact-when-using-releasestart-with-looping-enabled/14?_=1781354181861

    I haven't gotten around to testing it with 48kHz samples yet.
    But by now I've found enough use cases to split apart the sections into dedicated samplers.

  • 0 Votes
    3 Posts
    65 Views
    dannytaurusD

    @chimaera_09 Make the button show/hide a panel. Use the panel to house all your extra controls.

    const pnlSettings = Content.getComponent("pnlSettings"); const btnSettings = Content.getComponent("btnSettings"); btnSettings.setControlCallback(btnSettingsControl); inline function btnSettingsControl(component, value) { pnlSettings.showControl(value); // button shows/hides the panel }

    You can add a button in the panel to close it too:

    const btnSettingsClose = Content.getComponent("btnSettingsClose"); btnSettingsClose.setControlCallback(btnSettingsCloseControl); inline function btnSettingsCloseControl(component, value) { if (value) { pnlSettings.showControl(false); btnSettings.setValue(0); // sets the 'off' state of the button } }
  • 1 Votes
    1 Posts
    50 Views
    No one has replied
  • 0 Votes
    11 Posts
    235 Views
    ustkU

    Speaking of which...

    https://github.com/christophhart/HISE/pull/984

    I can't believe the math were wrong the whole time
    -> upDecayTime was inverted...