HISE Logo Forum
    • Categories
    • Register
    • Login

    Resampling/sample degrade

    Scheduled Pinned Locked Moved General Questions
    unsolvedresampledegrade
    9 Posts 5 Posters 851 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.
    • R
      rzrsharpeprod
      last edited by rzrsharpeprod

      Hi everyone,

      I am trying to find the best way to resample or degrade the sound that is output l.
      Similar to if you manually resample something in DAW by reducing the sample rate hz, or similar to what the cymatics origins plugin does.

      I have tried the degrade FX module and also the sampleandhold script node but both introduce a robotic noise as part of the resampling.

      I thought I could possibly filter out the additional noise but the results weren't great.

      Can this effect be achieved and if so, what is the best way to implement it please?

      Thanks in advance

      R LindonL 2 Replies Last reply Reply Quote 0
      • R
        rzrsharpeprod @rzrsharpeprod
        last edited by

        @rzrsharpeprod said in Resampling/sample degrade:

        Hi everyone,

        I am trying to find the best way to resample or degrade the sound that is output l.
        Similar to if you manually resample something in DAW by reducing the sample rate hz, or similar to what the cymatics origins plugin does.

        I have tried the degrade FX module and also the sampleandhold script node but both introduce a robotic noise as part of the resampling.

        I thought I could possibly filter out the additional noise but the results weren't great.

        Can this effect be achieved and if so, what is the best way to implement it please?

        Thanks in advance

        I've had not had a reply on this unfortunately and this forum is excellent at offering help. So does that mean it's not possible or easy to implement?

        VorosMusicV 1 Reply Last reply Reply Quote 0
        • VorosMusicV
          VorosMusic @rzrsharpeprod
          last edited by VorosMusic

          @rzrsharpeprod
          I'm very unfamiliar with scriptnode, but I guess you could achieve your wished result there.
          Edit...Sorry, I didn't read well enough to see you already tried that 😬

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

            @rzrsharpeprod said in Resampling/sample degrade:

            Hi everyone,

            I am trying to find the best way to resample or degrade the sound that is output l.
            Similar to if you manually resample something in DAW by reducing the sample rate hz, or similar to what the cymatics origins plugin does.

            I have tried the degrade FX module and also the sampleandhold script node but both introduce a robotic noise as part of the resampling.

            I thought I could possibly filter out the additional noise but the results weren't great.

            Can this effect be achieved and if so, what is the best way to implement it please?

            Thanks in advance

            are you talking about bit reduction or sample rate reduction?

            HISE Development for hire.
            www.channelrobot.com

            R 1 Reply Last reply Reply Quote 0
            • R
              rzrsharpeprod @Lindon
              last edited by

              @Lindon Samplerate ideally. When I used the built in functions though they introduced robotic sounding artifacts which is something I was trying to avoid as it doesn't sound good.

              What I'm hoping to achieve is something similar to when you manually reduce the samplerate & resample in DAW. It gives it that underwater effect for want of a better description.
              If you are familiar with the free Cymatics Origins plugin, the big dial in the middle of the UI does the same thing as resampling in DAW but in real time.

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

                I‘m just talking about the sampleandhold node here - the degrade FX is deprecated and should have been removed ages ago.

                The robotic artifacts come from the interpolation algorithm that the sample and hold node is using, which is none - it just picks up a sample and then outputs it as static value until the next interval (exactly what sample and hold means). For a better sounding effect you would have to introduce some interpolation methods (eg. ramping between the samples values or doing cubic splines), but that‘s currently not built into the node.

                Making a sampleandramp node could be a fun excercise for SNEX though…

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

                  Yes, I can verify what the last post said, it's a fun exercise:

                  template <int NV> struct sampleandramp
                  {
                  	SNEX_NODE(sampleandramp);
                  	
                  	// A compile time array of ramper objects
                  	// (sfloat is a built-in SNEX type for 
                  	// ramping between values for parameter
                  	// smoothing.
                  	span<sfloat, 2> rampers;
                  	
                  	double sampleRate = 44100.0;
                  	double fadeTimeMs = 1.0 / 44100.0 * 1000.0;
                  	
                  	// Initialise the processing specs here
                  	void prepare(PrepareSpecs ps)
                  	{
                  		sampleRate = ps.sampleRate;
                  
                  		// set the fade time again
                  		// (for some reason, iterating over the arra
                  		// throws a SNEX compilation error, so we have
                  		// to spell it out for each element)...
                  		rampers[0].prepare(sampleRate, fadeTimeMs);
                  		rampers[1].prepare(sampleRate, fadeTimeMs);
                  	}
                  	
                  	// Reset the processing pipeline here
                  	void reset()
                  	{
                  		// This will reset the ramp position, so when you bypass / unbypass the node it will
                  		// not pick up from the old value and cause clicks.
                  		rampers[0].reset();
                  		rampers[1].reset();
                  	}
                  	
                  	float calculateSample(float input, sfloat& ramper)
                  	{
                  		// if the ramper isn't smoothing, it's waiting for
                  		// the next input
                  		if(!ramper.isActive())
                  			ramper.set(input);
                  
                  		// this will calculate the next ramp value and
                  		// update the internal state
                  		return ramper.advance();
                  	}
                  	
                  	// Process the signal as frame here
                  	template <int C> void processFrame(span<float, C>& data)
                  	{
                  		data[0] = calculateSample(data[0], rampers[0]);
                  		
                  		if(C != 1)
                  			data[1] = calculateSample(data[1], rampers[1]);
                  	}
                  	
                  	// Process the signal here
                  	template <typename ProcessDataType> void process(ProcessDataType& data)
                  	{
                  		// We'll only use frame processing here...
                  		auto pd = data.toFrameData();
                  		
                  		while(pd.next())
                  			processFrame(pd.toSpan());
                  	}
                  	
                  	void handleHiseEvent(HiseEvent& e){}
                  	void setExternalData(const ExternalData& d, int index){}
                  	
                  	template <int P> void setParameter(double v)
                  	{
                  		if(P == 0) // Factor (1 - 64 with step size 1)
                  		{
                  			const auto factor = Math.range(v, 1.0, 64.0);
                  			
                  			// internally it will calculate the steps in
                  			// samples so this is two unnecessary divisions
                  			// but we get to use the built in type
                  			fadeTimeMs = (factor / sampleRate) * 1000.0;
                  			
                  			rampers[0].prepare(sampleRate, fadeTimeMs);
                  			rampers[1].prepare(sampleRate, fadeTimeMs);
                  		}
                  	}
                  };
                  

                  The artifacts are still there (linear interpolation is not a good interpolation algorithm), but it's already way better than sampleandhold.

                  R A 2 Replies Last reply Reply Quote 4
                  • R
                    rzrsharpeprod @Christoph Hart
                    last edited by rzrsharpeprod

                    @Christoph-Hart said in Resampling/sample degrade:

                    Yes, I can verify what the last post said, it's a fun exercise:

                    template <int NV> struct sampleandramp
                    {
                    	SNEX_NODE(sampleandramp);
                    	
                    	// A compile time array of ramper objects
                    	// (sfloat is a built-in SNEX type for 
                    	// ramping between values for parameter
                    	// smoothing.
                    	span<sfloat, 2> rampers;
                    	
                    	double sampleRate = 44100.0;
                    	double fadeTimeMs = 1.0 / 44100.0 * 1000.0;
                    	
                    	// Initialise the processing specs here
                    	void prepare(PrepareSpecs ps)
                    	{
                    		sampleRate = ps.sampleRate;
                    
                    		// set the fade time again
                    		// (for some reason, iterating over the arra
                    		// throws a SNEX compilation error, so we have
                    		// to spell it out for each element)...
                    		rampers[0].prepare(sampleRate, fadeTimeMs);
                    		rampers[1].prepare(sampleRate, fadeTimeMs);
                    	}
                    	
                    	// Reset the processing pipeline here
                    	void reset()
                    	{
                    		// This will reset the ramp position, so when you bypass / unbypass the node it will
                    		// not pick up from the old value and cause clicks.
                    		rampers[0].reset();
                    		rampers[1].reset();
                    	}
                    	
                    	float calculateSample(float input, sfloat& ramper)
                    	{
                    		// if the ramper isn't smoothing, it's waiting for
                    		// the next input
                    		if(!ramper.isActive())
                    			ramper.set(input);
                    
                    		// this will calculate the next ramp value and
                    		// update the internal state
                    		return ramper.advance();
                    	}
                    	
                    	// Process the signal as frame here
                    	template <int C> void processFrame(span<float, C>& data)
                    	{
                    		data[0] = calculateSample(data[0], rampers[0]);
                    		
                    		if(C != 1)
                    			data[1] = calculateSample(data[1], rampers[1]);
                    	}
                    	
                    	// Process the signal here
                    	template <typename ProcessDataType> void process(ProcessDataType& data)
                    	{
                    		// We'll only use frame processing here...
                    		auto pd = data.toFrameData();
                    		
                    		while(pd.next())
                    			processFrame(pd.toSpan());
                    	}
                    	
                    	void handleHiseEvent(HiseEvent& e){}
                    	void setExternalData(const ExternalData& d, int index){}
                    	
                    	template <int P> void setParameter(double v)
                    	{
                    		if(P == 0) // Factor (1 - 64 with step size 1)
                    		{
                    			const auto factor = Math.range(v, 1.0, 64.0);
                    			
                    			// internally it will calculate the steps in
                    			// samples so this is two unnecessary divisions
                    			// but we get to use the built in type
                    			fadeTimeMs = (factor / sampleRate) * 1000.0;
                    			
                    			rampers[0].prepare(sampleRate, fadeTimeMs);
                    			rampers[1].prepare(sampleRate, fadeTimeMs);
                    		}
                    	}
                    };
                    

                    The artifacts are still there (linear interpolation is not a good interpolation algorithm), but it's already way better than sampleandhold.

                    Thankyou @Christoph-Hart I will have a go with that code and try to implement it into my project and see how it works out. The assist is very much appreciated

                    1 Reply Last reply Reply Quote 0
                    • A
                      audiolyf @Christoph Hart
                      last edited by

                      @Christoph-Hart Is it possible to get at those inbetweens too and not just integers splitting the sample rate in half? For example if I wanted to go from 44100 to 35280?

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

                      27

                      Online

                      1.7k

                      Users

                      11.7k

                      Topics

                      102.0k

                      Posts