Forum
    • Categories
    • Register
    • Login

    (ScriptNode) Smeary Reverb / Washy Cymbals?

    Scheduled Pinned Locked Moved ScriptNode
    10 Posts 3 Posters 141 Views
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • iamlampreyI
      iamlamprey
      last edited by

      I'm noodling at physically modeled drums, specifically cymbals and I need an efficient way to "smear" the excitation impulse

      I know the typical route is to use allpass filters in the delay line, but I find I have to use a math.mul at 0.5 just to keep the audio from blowing up.

      I currently have 5 delays with different fractional delay times and I'm also passing a long noise tail into it but it just sounds like a noisy sawtooth buzz rather than a nice chorusy wash.

      Not sure how to proceed towards that metallic ringing without overloading the delay lines or the CPU

      LindonL 1 Reply Last reply Reply Quote 0
      • LindonL
        Lindon @iamlamprey
        last edited by

        @iamlamprey

        https://www.youtube.com/watch?v=netcpYINyBQ

        HISE Development for hire.
        www.channelrobot.com

        iamlampreyI 1 Reply Last reply Reply Quote 1
        • iamlampreyI
          iamlamprey @Lindon
          last edited by

          @Lindon Yep that's the one I'm following :)

          he's using an airwindows plugin for the allpass but the HISE allpass node sounds nothing like that, not sure how all the coefficient stuff works

          I ended up going a harmonic + stochastic approach which is showings its obvious limitations

          LindonL 1 Reply Last reply Reply Quote 0
          • LindonL
            Lindon @iamlamprey
            last edited by

            @iamlamprey you could always import the Airwindows code.. Chris is pretty open to that.

            HISE Development for hire.
            www.channelrobot.com

            iamlampreyI 1 Reply Last reply Reply Quote 1
            • iamlampreyI
              iamlamprey @Lindon
              last edited by

              @Lindon That's a good idea, I'll keep it in the back pocket for now because I want to keep everything in scriptnode but if I can't figure it out I'll make a wrapper

              Christoph HartC 1 Reply Last reply Reply Quote 0
              • Christoph HartC
                Christoph Hart @iamlamprey
                last edited by

                Haha yeah I‘ve seen that video too and thought damn thats not what a DAW is made for.

                LindonL 1 Reply Last reply Reply Quote 1
                • LindonL
                  Lindon @Christoph Hart
                  last edited by

                  @Christoph-Hart said in (ScriptNode) Smeary Reverb / Washy Cymbals?:

                  Haha yeah I‘ve seen that video too and thought damn thats not what a DAW is made for.

                  yeah its extreme .. but to be admired in some ways....

                  HISE Development for hire.
                  www.channelrobot.com

                  1 Reply Last reply Reply Quote 1
                  • iamlampreyI
                    iamlamprey
                    last edited by

                    Okie, here's the wrapper if anyone else needs it:

                    // ==================================| Third Party Node Template |==================================
                    
                    #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 phaseNudge: public data::base
                    {
                    	// Metadata Definitions ------------------------------------------------------------------------
                    	
                    	SNEX_NODE(phaseNudge);
                    	
                    	struct MetadataClass
                    	{
                    		SN_NODE_ID("phaseNudge");
                    	};
                    	
                    	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;
                    	static constexpr int NumSliderPacks = 0;
                    	static constexpr int NumAudioFiles = 0;
                    	static constexpr int NumFilters = 0;
                    	static constexpr int NumDisplayBuffers = 0;		
                    	
                    	void prepare(PrepareSpecs specs)
                    	{
                    		
                    	}
                    	
                    	void reset()
                    	{
                    
                    	}
                    	
                    	void handleHiseEvent(HiseEvent& e)
                    	{
                    		(void)e;
                    	}
                    
                    	double dL[1503];
                    	double dR[1503];
                    	int one = 1;
                    	int maxdelay = 9001;
                        double A = 0.0;
                        double B = 1.0;
                        uint32_t fpdL;
                    	uint32_t fpdR;
                    	int allpasstemp;
                    	double outallpass = 0.618033988749894848204586;
                    	int maxdelayTarget = (int)(pow(A,3)*1501.0);
                    	double wet = B;
                    	double bridgerectifier;	
                    	double inputSampleL;
                    	double inputSampleR;
                    	double drySampleL;
                    	double drySampleR;
                    
                    	template <typename T> void process(T& data)
                    	{
                    		const int numSamples = data.getNumSamples();
                            const int numChannels = jmin(2, (int)data.getNumChannels());
                            maxdelayTarget = (int)(pow(A, 3) * 1501.0);
                            wet = B;
                    
                    		dyn<float> chL, chR;
                            int idx = 0;
                    
                            for (auto ch : data)
                            {
                                if      (idx == 0) chL = data.toChannelData(ch);
                                else if (idx == 1) chR = data.toChannelData(ch);
                                ++idx;            
                            }
                    
                            if (numChannels == 1) chR = chL;
                    
                            for (int s = 0; s < numSamples; ++s)
                            {
                            	double dryL = chL[s];
                            	double dryR = numChannels > 1 ? chR[s] : dryL;        	
                            	double xL = chL[s];
                            	double xR = numChannels > 1 ? chR[s] : xL;
                    
                            	// might add dithering later
                    
                            	// bridge rectifier
                    
                            	xL /= 4.0;
                    			xR /= 4.0;
                    
                    			double br = std::fabs(xL);
                    			br = std::sin(br);
                    			if (xL > 0) xL = br;
                    			else xL = -br;
                    
                    			br = std::fabs(xR);
                    			br = std::sin(br);
                    			if (xR > 0) xR = br;
                    			else xR = -br;			
                    
                    			// allpass		
                    				
                    			if (std::fabs(maxdelay - maxdelayTarget) > 1500) maxdelay = maxdelayTarget;
                    
                    			if (maxdelay < maxdelayTarget) 
                    			{
                    				maxdelay++;
                    				dL[maxdelay] = (dL[0] + dL[maxdelay-1]) / 2.0;
                    				dR[maxdelay] = (dR[0] + dR[maxdelay-1]) / 2.0;
                    			}
                    
                    			if (maxdelay > maxdelayTarget) 
                    			{
                    				maxdelay--;
                    				dL[maxdelay] = (dL[0] + dL[maxdelay]) / 2.0;
                    				dR[maxdelay] = (dR[0] + dR[maxdelay]) / 2.0;
                    			}
                    
                    			allpasstemp = one - 1;
                    			if (allpasstemp < 0 || allpasstemp > maxdelay) allpasstemp = maxdelay;
                    
                    			xL -= dL[allpasstemp] * outallpass;
                    			xR -= dR[allpasstemp] * outallpass;
                    			dL[one] = xL;
                    			dR[one] = xR;
                    			xL *= outallpass;
                    			xR *= outallpass;
                    			one--;
                    			if (one < 0 || one > maxdelay) { one = maxdelay; }
                    			xL += (dL[one]);
                    			xR += (dR[one]);
                    
                    			// second bridge rectifier stage
                    
                    			br = std::fabs(xL);
                    			br = 1.0 - std::cos(br);
                    			if (xL > 0) xL -= br;
                    			else xL += br;
                    
                    			br = std::fabs(xR);
                    			br = 1.0 - std::cos(br);
                    			if (xR > 0) xR -= br;
                    			else xR += br;
                    
                    			xL *= 4.0;
                    			xR *= 4.0;
                    			
                    			// apply dry / wet
                    
                    			if (wet < 1.0)
                    			{
                    				xL = (dryL * (1.0 - wet)) + (xL * wet);
                    				xR = (dryR * (1.0 - wet)) + (xR * wet);
                    			}
                    
                    			// apply dither goes here
                    
                    			// write back to channelData
                    			chL[s] = xL;
                    			chR[s] = xR;
                    		}	        
                    	}	
                    	
                    
                    	template <typename T> void processFrame(T& data)
                    	{
                    
                    	}	
                    	
                    	int handleModulation(double& value)
                    	{
                    		
                    		return 0;
                    		
                    	}
                    	
                    	void setExternalData(const ExternalData& data, int index)
                    	{
                    		
                    	}
                    	
                    	template <int P> void setParameter(double v)
                    	{
                    		switch (P)
                    		{
                    			case 0: { A = v; break; }
                    			case 1: { B = v; break; }
                    		}		
                    	}
                    	
                    	void createParameters(ParameterDataList& data)
                    	{
                    		{
                    			parameter::data p("PhaseNudge", { 0.0, 1.0 });
                    			registerCallback<0>(p);
                    			p.setDefaultValue(0.5);
                    			data.add(std::move(p));
                    		}
                    		{
                    			parameter::data p("Dry/Wet", { 0.0, 1.0 });
                    			registerCallback<1>(p);
                    			p.setDefaultValue(0.5);
                    			data.add(std::move(p));
                    		}		
                    	}
                    }; // end struct
                    } // end namespace
                    
                    
                    
                    

                    It's missing the dithering stuff, but it sounds basically identical to the original implementation, just make sure to set up the third party node using the template and call it "phaseNudge.h"

                    Christoph HartC 1 Reply Last reply Reply Quote 0
                    • Christoph HartC
                      Christoph Hart @iamlamprey
                      last edited by

                      @iamlamprey haha everybody always rips out the dither stuff from air windows :)

                      iamlampreyI 1 Reply Last reply Reply Quote 1
                      • iamlampreyI
                        iamlamprey @Christoph Hart
                        last edited by

                        @Christoph-Hart said in (ScriptNode) Smeary Reverb / Washy Cymbals?:

                        @iamlamprey haha everybody always rips out the dither stuff from air windows :)

                        i assume he has it there for a reason but most DAWs apply dithering now anyway and I can't hear a difference lol

                        1 Reply Last reply Reply Quote 0
                        • First post
                          Last post

                        36

                        Online

                        2.2k

                        Users

                        13.3k

                        Topics

                        115.6k

                        Posts