• Best Way to Implement an Infinite Text Console?

    Solved
    5
    0 Votes
    5 Posts
    182 Views
    clevername27C

    @ustk Very cool - I gave up a lot quicker, lol. Thanks on the offer, very kind of you.

  • Controlling FX from a slider?

    6
    0 Votes
    6 Posts
    149 Views
    G

    @d-healey Thanks David

  • Open-Source Faust Transient Shaper

    11
    5 Votes
    11 Posts
    1k Views
    orangeO

    Does this code work for you?

    When I load this, as soon as I tweak the Sustain knob, it breaks the sound and creates sound glitch.

    declare name "Whetstone Transient Shaper"; declare author "Evermind"; import("stdfaust.lib"); WINDOW = 30 / 1000; low_cutoff = hslider("v:Whetstone Transient Shaper/[2]Low Cutoff[unit:Hz]",10,10,20000,10); high_cutoff = hslider("v:Whetstone Transient Shaper/[3]High Cutoff[unit:Hz]", 20000,20,20000,10); do_monitor = button("v:Whetstone Transient Shaper/h:[4]Monitoring/[0]Monitor selected band") : ba.toggle : vbargraph("v:Whetstone Transient Shaper/h:[4]Monitoring/[1]ON[style:led]", 0, 1); attack = hslider("v:Whetstone Transient Shaper/[0]Attack[unit:dB]",0,-12,+12,0.1) : ba.db2linear : si.smoo; sustain = hslider("v:Whetstone Transient Shaper/[1]Sustain[unit:dB]",0,-12,+12,0.1) : ba.db2linear : si.smoo; process = sp.stereoize(split_shape_merge); split_shape_merge = _ : split_active_and_passive : (_ <: _ * get_gain(_ : change)), ba.bypass1(do_monitor != 1, *(0)) :> _; //split signal into two parts $active, $passive //$active is resonant low- and high-passed between low_cutoff and high_cutoff respectively. This is fed directly to output if monitoring is on //$passive is resonant high- and low-passed between low_cutoff and high-cutoff respectively split_active_and_passive = _ <: (fi.resonhp(low_cutoff, 1, 1) : fi.resonlp(high_cutoff, 1, 1)), (fi.resonlp(low_cutoff, 1, 1) + fi.resonhp(high_cutoff, 1, 1)); //$active is analyzed with RMS over N ms divided by a lag filter applied to the RMS to get a rise speed over time to get $change change = ba.slidingRMS(ba.sec2samp(WINDOW)) <: _ - si.lag_ud(WINDOW, WINDOW); //If $change is positive, $gain is $attack //If $change is negative, $gain is $sustain //Smooth $gain get_gain(x) = ba.if(x > 0, attack,sustain) : si.lag_ud(WINDOW,WINDOW);
  • Aliasing when Resampling (C++ Project)

    Solved
    6
    0 Votes
    6 Posts
    213 Views
    griffinboyG

    @Christoph-Hart

    Yep, took it down immediately realising the sillyness!

    This is a good solution now, it seems to work fine.
    I've not done resampling before, I was tying myself in knots. Best to make something functional and robust before looking at optimisations.

    This seems to work so I'll leave it here in case anyone needed to see the interpolation method. I need to do more learning myself

    // ==========================| Sampler v0.58 : by Griffinboy |========================== #pragma once #include <JuceHeader.h> #include <array> namespace project { using namespace juce; using namespace hise; using namespace scriptnode; // Template class for a sampler with a specified number of voices (NV) template <int NV> struct Griffin_Sampler : public data::base { SNEX_NODE(Griffin_Sampler); struct MetadataClass { SN_NODE_ID("Griffin_Sampler"); }; // ==========================| Node Properties |========================== // Define properties of the node static constexpr bool isModNode() { return true; } // Indicates this is a modulation node static constexpr bool isPolyphonic() { return NV > 1; } // Determines if the sampler is polyphonic static constexpr bool hasTail() { return false; } // Indicates if the node has a tail (sustain) static constexpr bool isSuspendedOnSilence() { return false; } // Determines if processing is suspended on silence static constexpr int getFixChannelAmount() { return 2; } // Fixed number of audio channels // Define the number of various components static constexpr int NumTables = 0; static constexpr int NumSliderPacks = 0; static constexpr int NumAudioFiles = 1; static constexpr int NumFilters = 0; static constexpr int NumDisplayBuffers = 0; // ==========================| Global Variables |========================== using InterpolatorType = index::hermite<index::unscaled<double, index::clamped<0, false>>>; static const int NUM_CHANNELS = 2; // Number of audio channels ExternalData data; // External data for the sampler span<dyn<float>, NUM_CHANNELS> sample; // Sample data for each channel double sr = 0.0; // Sample rate double file_sr = 0.0; // File sample rate // Looping and playback parameters double loopStart = 0.0; double loopEnd = 1.0; bool loopEnabled = false; double pitchModulation = 0.0; double speedMultiplier = 1.0; // Structure to hold voice-specific data struct VoiceData { double uptime = 0.0; // Time since the voice started playing double delta = 1.0 / (1 << 28); // Increment per sample int midiNote = 60; // MIDI note number bool isLooping = false; // Looping state bool isPlaying = false; // Playback state // Resets the voice data void reset() { uptime = 0.0; isPlaying = true; } // Advances the playback position and handles looping double bump(double loopStart, double loopEnd, double numSamples) { if (!isPlaying) return numSamples; double rv = uptime; uptime += delta; if (isLooping && uptime >= loopEnd && loopEnd > loopStart) { double loopLength = loopEnd - loopStart; uptime = loopStart + std::fmod(uptime - loopStart, loopLength); } else if (uptime >= numSamples) { uptime = numSamples; isPlaying = false; } return rv; } }; PolyData<VoiceData, NV> voiceData; // Container for voice data ModValue gate; // Modulation value for gate std::array<float, 128> pitchRatios; // Precomputed pitch ratios for MIDI notes // ==========================| Prepare |========================== // Prepares the sampler for playback void prepare(PrepareSpecs specs) { voiceData.prepare(specs); sr = specs.sampleRate; initPitchRatios(); if (data.numSamples > 0 && sr != 0.0) { updateAllVoiceDeltas(); } validateLoopPoints(); } // Initializes pitch ratios for MIDI notes void initPitchRatios() { constexpr int rootNote = 60; // Middle C for (int i = 0; i < 128; ++i) pitchRatios[i] = std::pow(2.0f, (i - rootNote) / 12.0f); } // Validates and adjusts loop points void validateLoopPoints() { if (data.numSamples > 0) { loopStart = juce::jlimit(0.0, 1.0, loopStart); loopEnd = juce::jlimit(loopStart, 1.0, loopEnd); } else { loopStart = 0.0; loopEnd = 1.0; } } // ==========================| Reset |========================== // Resets all voices void reset() { for (auto& v : voiceData) v.reset(); } // ==========================| Process |========================== // Processes audio data template <typename ProcessDataType> void process(ProcessDataType& data) { int numSamples = data.getNumSamples(); if (numSamples == 0 || this->data.numSamples == 0) return; DataReadLock sl(this->data); auto& v = voiceData.get(); auto& fixData = data.template as<ProcessData<NUM_CHANNELS>>(); auto audioBlock = fixData.toAudioBlock(); processBlock(audioBlock, v, numSamples); this->data.setDisplayedValue(v.uptime); gate.setModValueIfChanged(static_cast<double>(v.isPlaying)); } // Processes a block of audio samples void processBlock(juce::dsp::AudioBlock<float>& audioBlock, VoiceData& v, int numSamples) { auto* leftChannelData = audioBlock.getChannelPointer(0); auto* rightChannelData = audioBlock.getChannelPointer(1); double numSamplesDouble = static_cast<double>(data.numSamples); double loopStartSamples = loopStart * numSamplesDouble; double loopEndSamples = loopEnd * numSamplesDouble; for (int i = 0; i < numSamples; ++i) { double thisUptime = v.bump(loopStartSamples, loopEndSamples, numSamplesDouble); if (v.isPlaying) { InterpolatorType idx(thisUptime); leftChannelData[i] = sample[0][idx]; rightChannelData[i] = sample[1][idx]; } else { leftChannelData[i] = 0.0f; rightChannelData[i] = 0.0f; } } } template <typename FrameDataType> void processFrame(FrameDataType& fd) { // Implement if needed } // ==========================| Set Parameter |========================== // Sets a parameter value and validates if necessary template <int P> void setParameter(double v) { bool needsValidation = false; if (P == 0) { loopStart = v; needsValidation = true; } else if (P == 1) { loopEnd = v; needsValidation = true; } else if (P == 2) { loopEnabled = v > 0.5; } else if (P == 3) { pitchModulation = v; updateAllVoiceDeltas(); } else if (P == 4) { speedMultiplier = v; updateAllVoiceDeltas(); } if (needsValidation) { validateLoopPoints(); } } // ==========================| Create Parameters |========================== // Creates and registers parameters for the sampler void createParameters(ParameterDataList& data) { { parameter::data p("Loop Start", { 0.0, 1.0, 0.01 }); registerCallback<0>(p); p.setDefaultValue(0.0); data.add(std::move(p)); } { parameter::data p("Loop End", { 0.0, 1.0, 0.01 }); registerCallback<1>(p); p.setDefaultValue(1.0); data.add(std::move(p)); } { parameter::data p("Loop Enable", { 0.0, 1.0, 1.0 }); registerCallback<2>(p); p.setDefaultValue(0.0); data.add(std::move(p)); } { parameter::data p("Pitch", { -12.0, 12.0, 0.001 }); registerCallback<3>(p); p.setDefaultValue(0.0); data.add(std::move(p)); } { parameter::data p("Speed", { 0.5, 2.0, 0.01 }); registerCallback<4>(p); p.setDefaultValue(1.0); data.add(std::move(p)); } } // ==========================| External Data |========================== // Sets external data for the sampler void setExternalData(const ExternalData& ed, int index) { data = ed; ed.referBlockTo(sample[0], 0); ed.referBlockTo(sample[1], 1); if (data.numSamples > 0 && sr != 0.0) { updateAllVoiceDeltas(); validateLoopPoints(); } } // ==========================| Handle HISE Event |========================== // Handles MIDI events for note on and note off void handleHiseEvent(HiseEvent& e) { if (e.isNoteOn()) { auto& v = voiceData.get(); v.midiNote = e.getNoteNumber(); v.delta = calculateDelta(v.midiNote); v.reset(); v.isLooping = loopEnabled; } else if (e.isNoteOff()) { auto& v = voiceData.get(); if (v.midiNote == e.getNoteNumber()) { v.isPlaying = false; } } } // ==========================| Modulation Slot |========================== // Handles modulation changes bool handleModulation(double& value) { return gate.getChangedValue(value); } // ==========================| Helper Functions |========================== // Updates the delta for all voices based on current parameters void updateAllVoiceDeltas() { for (auto& v : voiceData) { v.delta = calculateDelta(v.midiNote); } } // Calculates the delta for a given MIDI note double calculateDelta(int midiNote) { double pitchRatio = std::pow(2.0, pitchModulation / 12.0); return (data.sampleRate / sr) * pitchRatios[midiNote] * pitchRatio * speedMultiplier; } }; }
  • Event data inside of External c++ node

    Solved
    6
    0 Votes
    6 Posts
    357 Views
    Christoph HartC

    @griffinboy said in Event data inside of External c++ node:

    I must not understand how it's working.

    The secret ingredient is this template container class:

    Link Preview Image HISE | ScriptNode | PolyData

    My Funky Summary

    favicon

    (docs.hise.dev)

    Relevant part:

    // If you want to change the data through a parameter callback // it's recommended to use the iterator. template void setParameter(double value) { // the iterator will either loop through // all data elements if it's outside a // voice rendering (most likely caused by a UI callback) // or just one element of the active voice (most likely used // by modulation inside the audio rendering). for(auto& d: data) d = (float)value; }

    So if you're modulating a parameter that is changing a PolyData object through a cable connection, it will change only the data for the current voice if the source event is happening in the audio rendering (like the control node) OR change all voices if the source event is outside of the audio rendering context (like when moving a slider).

    Be aware that this is multithreading-safe, so if you call this from the UI thread while the audio is rendering, it will still correctly detect that it should change all voices (it achieves this by registering the audio thread ID to the polyvoice manager that you will give it in the prepare call)

  • Loris processCustom with Lambda arguments?

    6
    0 Votes
    6 Posts
    223 Views
    Christoph HartC

    @iamlamprey yes, loris calls into the function with a single argument containing the data object, so if you supply more arguments it will be ignored.

    The lambda way would also work, but you cannot pass literal values (in this case the 440.0), but it needs to be a locally scoped variable.

    Another option would be to use a variable outside of the function that you set to 440.0.

  • Need help with importing samples via script

    Unsolved
    6
    0 Votes
    6 Posts
    200 Views
    ?

    Another error related to this line:

    var importedSamples = Sampler1.asSampler().importSamples([path], false);

    Exception thrown: read access violation. std::_Atomic_address_as<long,std::_Atomic_padded<int> >(...) returned 0xFFFFFFFFFFFFFFFF.

    This Atomic file is part of VS2022 so I'm in uncharted waters now I think 😲

  • Remote Website Doesn't Render with WebView in Executable

    Solved
    3
    0 Votes
    3 Posts
    259 Views
    clevername27C

    @Adam_G Solved! I don't recall if there is a HISE setting that you also need, but here's the code:

    // This file has the redirect to the internet. var startingPage = FileSystem.getFolder(FileSystem.AudioFiles).getParentDirectory().getChildFile("Images/html/index.html"); web_DOCS_CoreHTML_GUI.set("enableCache", true); web_DOCS_CoreHTML_GUI.reset(); web_DOCS_CoreHTML_GUI.setIndexFile(startingPage);

    In your Images folder, create a folder called "htm" (though you can call it anything), and place your "index.html" (which likewise, can be any file name ending in the html extension). In this file, use this meta-tag.

    <!doctype html> <html> <head> <meta charset="UTF-8"> <title></title> <meta http-equiv="refresh" content="0; URL=https://www.ferretsfightingllamas.com" /> </head> <body> </body> </html>
  • Loris applyFilter doesn't seem to work

    1
    0 Votes
    1 Posts
    79 Views
    No one has replied
  • Timer Fade

    4
    0 Votes
    4 Posts
    252 Views
    d.healeyD

    @meto396 Yes, you can call startTimer() again to set a new time, even while the timer is already running.

  • if (value >= -1) | issue with IF function

    5
    0 Votes
    5 Posts
    171 Views
    trillbillyT

    @d-healey Ahhh, ok I see. Let me implement this into the project. Thanks again.

  • json.length not working?

    Solved
    3
    0 Votes
    3 Posts
    104 Views
    A

    @Christoph-Hart yeah of course, I thought I hallucinated it for a second, probably because so many array methods work on objects, too. thanks.

  • round robin random

    5
    0 Votes
    5 Posts
    328 Views
    M

    @Noahdeetz Sorry I'm using audio loop players and no sampler to change the sounds straight from the interface

  • Broadcasters best practices

    Solved
    53
    1 Votes
    53 Posts
    3k Views
    d.healeyD

    @Christoph-Hart Duly noted, I'll continue with my other method then 😀

  • Play only the lowest note of a chord

    8
    0 Votes
    8 Posts
    183 Views
    Oli UllmannO

    @d-healey Yes, I will try that.

  • every note a new sample

    2
    0 Votes
    2 Posts
    159 Views
    DabDabD

    @treynterrio said in every note a new sample:

    if I play C3 5 times, it plays all samples once and starts again at sample 1 the 6th time it is pressed.

    You need Round Robin for that. Record each key's samples [zone] from the instrument you want to imitate, lets suppose Piano. Record each notes and stack each velocity with RR.
    Watch @d-healey
    https://www.youtube.com/watch?v=UIqqlV5mgG4
    https://www.youtube.com/watch?v=ZbHncYOagvg

  • Help with Dynamic FX System - Duplicating and Mapping UI Panels

    Unsolved
    6
    0 Votes
    6 Posts
    402 Views
    HISEnbergH

    @griffinboy Great I will post here if I come across anything.

  • Help making a knob turn an effect on and off

    3
    0 Votes
    3 Posts
    132 Views
    B

    @Lindon Champion! Thankyou.

  • 0 Votes
    7 Posts
    304 Views
    F

    @d-healey

    I edited to fix completely tired misinformation etc in my post but yes I had a bunch of regs left over from misusing them and basically haven’t bothered since this is in module and UI builder code but yes I’ll change them.

    Taking a 5 month leave from working on this has not been great :D

  • How does builder.connectToScript() work?

    5
    0 Votes
    5 Posts
    263 Views
    Christoph HartC

    @Fergler yeah you can use this method with float attributes only.

    The connectToScript function is almost correct, but the reference does need to use the Scripts folder in its path:

    {PROJECT_FOLDER}ScriptProcessors/MyProcessor.js should work, however it‘s highly recommended to move the script out of this directory as it will be replaced on the next save.

15

Online

1.8k

Users

12.1k

Topics

104.9k

Posts