Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 18 of 18

Thread: Gate

  1. #1
    Senior Member
    Join Date
    Jul 2014
    Posts
    140

    Gate

    It's common in live performance to use gates on things like drum kits to clean up the sound from the mic on each drum.
    (https://en.wikipedia.org/wiki/Noise_gate)

    From an audio waveform perspective, it looks a little like this:
    Click image for larger version. 

Name:	Gate in action.png 
Views:	134 
Size:	8.2 KB 
ID:	10506
    Top trace is before gate, bottom is after gate.

    Gates tend to have threshold/attack/hold/release/floor settings.

    Graphically shown here with exaggerated settings:
    Click image for larger version. 

Name:	Gate.png 
Views:	158 
Size:	27.4 KB 
ID:	10507
    (Threshold: 0.3, Floor: 0.1)

    Source (effect_gate.h):
    https://github.com/macaba/Audio

    I'm happy to create a pull request if this is suitable for the main repo.

  2. #2
    Senior Member Blackaddr's Avatar
    Join Date
    Mar 2017
    Location
    Canada
    Posts
    328
    Cool. Gates are an essential part of my VST based live gigging rig.

    How does yours compare with the Envelope filter effect already in the library? I've not used it but it has attack, hold, delay, sustain, release controls.

  3. #3
    Senior Member
    Join Date
    Jul 2014
    Posts
    140
    Quote Originally Posted by Blackaddr View Post
    How does yours compare with the Envelope filter effect already in the library? I've not used it but it has attack, hold, delay, sustain, release controls.
    It's not a direct comparison as Envelope generator is externally triggered (using noteOn()) whereas a Gate is signal triggered (using threshold(n) to set trigger level).
    Envelope = for synthesis, Gate = for audio processing.
    To misuse the envelope as a gate would require a bit of glue logic in the user code - polling a 'peak' object to call noteOn() on the envelope. Also the envelope would need to be retriggerable, I'm not sure if the current one is.
    Last edited by macaba; 05-07-2017 at 06:20 PM.

  4. #4
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    25,221
    I recently improved the envelope object, and I'm looking to do more in June. The new version is a huge improvement, but I understand there's more work to be done.

    But I need feedback. The most helpful form of feedback is a test program which synthesizes or plays a specific sound and calls the envelope note on/off functions are specific times, to demonstrate the cases where clicks or other undesirable output happens. I get quite a bit of feedback that's really not very helpful. Test programs that actually demonstrate the limitations are the best way to get me to fix something...

    I'm also considering adding many more objects to the library with signal control inputs. A gate input to ADSR control signal is one of the ideas on my list. To achieve the envelope, you'd feed that ADSR control signal to the multiplier object (the equivalent of a voltage controlled amplifier). This sort of usage will offer much finer timing and will probably feel familiar to people used to analog & modular synthesis. But it will cost significantly higher CPU usage. The existing envelope effect uses well under 1% CPU on Teensy 3.2. This sort of control signal approach is likely to be around 2% to 5%.

  5. #5
    Senior Member
    Join Date
    Jul 2014
    Posts
    140
    Quote Originally Posted by PaulStoffregen View Post
    A gate input to ADSR control signal is one of the ideas on my list.
    I think there is a case of confused terminology here - A Noise Gate isn't a modular synthesis thing, it's an industry standard live audio processing thing.
    Example device:
    http://www.drawmer.com/company.php#201

    I guess it comes down to whether you're just aiming the audio library at synthesis applications, or if live audio is also in scope. The new object I've created is purely a live audio processing concept - it doesn't really have a place in synthesis.

    Edit:
    Apple have a nice definition here:
    https://documentation.apple.com/en/l...0%26tasks=true
    Last edited by macaba; 05-07-2017 at 10:57 PM.

  6. #6
    Member
    Join Date
    Dec 2016
    Location
    Apeldoorn, Netherlands
    Posts
    24
    I think gates can just as well have a place in synthesis. In fact some synthesizers include a rythmical gate effect.
    Besides that, I think you're missing some generalisation: a gate is nothing more than an automatic volume control that sets it's volume to 0 when the input falls below some threshold. If the library already provides all the building blocks, one could easily make a gate using those. So split audio signal to a level\peak detector and the vca audio input, compare the output level of the level detector with a DC level (threshold control). Mult the level with a envelope and you should have something like a gate,but the building blocks are generic enough to build other stuff as well, (compressors and what not). Maybe only thing missing is a comparator and maybe an inverter.

  7. #7
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    25,221
    Lately the effort on the audio library has been for synthesis stuff, mostly because it's been somewhat lacking in synthesis features. Certainly the intention is to support real-time signal processing, and play & record applications. Just because some work is recently going into improving features for one application doesn't mean all development will go that way!

  8. #8
    Senior Member
    Join Date
    Jul 2014
    Posts
    140
    Quote Originally Posted by PaulStoffregen View Post
    Certainly the intention is to support real-time signal processing, and play & record applications.
    Perfect, I'll keep releasing real-time oriented objects. When I've used them a lot and they're confirmed to be bug free, I'll look at doing pull requests.

    I've seen there is a F32 fork of the audio library for floats but it needed a bit of work before coming 'official' - can I help?

    I'd like to get this going for my Teensy 3.6, I think it makes sense to normalise any input source to +/- 1.0 and then objects like mixers won't clip (they'll just give out greater than 1.0, giving any downstream processing a chance to limit it to 1.0 before the output device).
    It's also serendipitous that 2^24 is the largest contiguous number that a 32-bit float can do before skipping integer values so a float can be confidently converted back to 24 bit int for those (non-official) 24 bit audio shields.
    Last edited by macaba; 05-10-2017 at 08:46 AM.

  9. #9
    I have just uploaded my dynamics object here https://github.com/MarkzP/AudioEffectDynamics
    It's a combination of gate/compressor/limiter that I modeled after a popular unit
    I'm certainly not done optimizing it, it doesn't work on the LC (yet) but that should be a good starting point

    Marc

  10. #10
    macaba,

    Been using your gate object. I love it thanks, was able to get the settings to replicate a noise pedal I got pretty well. Thanks.

  11. #11
    Hi, may I ask for a pull request to include this great object into the official library?
    Best regards,
    Christof

  12. #12
    Hi,
    to use this object for a guitar input signal it makes sense to bring in some hysteresis. The level to Switch on has to be higher than the Level to switch off.
    My very simple modification:
    Code:
    .....
    switch (state) {
    				case S_Floor:
    					currentGain = floorGain;
    					if(maxAbsSample > (2*thresholdLevelInt)) { // <==== Hysteresis
    						state = S_Attack;
    						processNextState = true;
    					}					
    					break;
    				case S_Attack:
    					currentGain += attackTimeDelta;
    					if(currentGain >= 1.0f) {
    						currentGain = 1.0f;
    						state = S_Hold;
    						processNextState = true;
    					}
    					break;
    				case S_Hold:
    					currentGain = 1.0f;
    					if(maxAbsSample > thresholdLevelInt)
    						break;			//Re-triggered. Also prevents infinite loop.
    					currentHoldTime += holdTimeDelta;
    					if(currentHoldTime >= 1.0f) {
    						currentHoldTime = 0.0f;
    						state = S_Release;
    						processNextState = true;
    					}
    					break;
    				case S_Release:
    					if(maxAbsSample > (2*thresholdLevelInt)) { //   <=== Hysteresis
    						state = S_Attack;
    						processNextState = true;
    						break;			//Re-triggered
    					}
    ....
    Best regards Christof

  13. #13
    I second cebersp's request to put this into the official library. I love it!

  14. #14
    I recently tried to use gate with my teensy 4.0 and had no such luck... It does not produce any errors but also has no effect on the sound. I tried chaging the settings to many different values, but no matter what I do the audio is unaffected. Unfortunately I am not aware of all of the changes in audio library code for a year or so (and since teensy 4.0). Can someone help me by taking a look at effect_gate.cpp and effect_gate.h to see if they can help me figure out what the issue is.

    https://github.com/macaba/Audio

    Here is my code as well.

    Thanks!

    Code:
    #include <Audio.h>
    #include <Wire.h>
    #include <SPI.h>
    #include <SD.h>
    #include <SerialFlash.h>
    #include <effect_gate.h>
    
    // GUItool: begin automatically generated code
    AudioControlSGTL5000     sgtl5000_1;
    AudioOutputI2S            i2s2;
    AudioSynthNoiseWhite     noise1; //xy=203,482
    AudioSynthSimpleDrum     drum1; //xy=203,522
    AudioMixer4              mixer1;         //xy=433,407
    AudioEffectGate          gate1;          //xy=687,440
    AudioConnection          patchCord1(noise1, 0, mixer1, 0);
    AudioConnection          patchCord2(drum1, 0, mixer1, 1);
    AudioConnection          patchCord3(mixer1, 0, gate1,0);
    AudioConnection          patchCord4(mixer1, 0, i2s2, 0);
    AudioConnection          patchCord5(gate1, 0, i2s2, 1);
    // GUItool: end automatically generated code
    
    unsigned long last_time = millis();
    
    void setup() {
      AudioMemory(10);
      
      noise1.amplitude(0.02);
      drum1.frequency(180);
      drum1.length(400);
      drum1.secondMix(0.3);
      drum1.pitchMod(0.7);
      mixer1.gain(1,1.6);
      
      gate1.threshold(0.2);
      gate1.attack(.001);
      gate1.release(10);
      gate1.hold(10);
      gate1.floor(.01);
      
      AudioProcessorUsageMaxReset();
      AudioMemoryUsageMaxReset();
    }
    
    
    void loop() {
      if(1) {
        if(millis() - last_time >= 1000) {
          Serial.print("Proc = ");
          Serial.print(AudioProcessorUsage());
          Serial.print(" (");    
          Serial.print(AudioProcessorUsageMax());
          Serial.print("),  Mem = ");
          Serial.print(AudioMemoryUsage());
          Serial.print(" (");    
          Serial.print(AudioMemoryUsageMax());
          Serial.println(")");
          last_time = millis();
          drum1.noteOn();
        }
      }
    }

  15. #15
    Junior Member
    Join Date
    Dec 2020
    Posts
    2
    I'd also love to have access to a gate effect - I've tried to merge in the changes macaba made above into the latest release, but have been unable to get the effect to work.

    I've noticed there's a few people above asking for a pull request for this - wondering if it would be possible to add this to the library as an effect?

  16. #16
    Quote Originally Posted by paniclemur View Post
    I'd also love to have access to a gate effect - I've tried to merge in the changes macaba made above into the latest release, but have been unable to get the effect to work.

    I've noticed there's a few people above asking for a pull request for this - wondering if it would be possible to add this to the library as an effect?
    To install the gate I first found the audio library folder on my computer, for me the folder location is C:\Program Files (x86)\Arduino\hardware\teensy\avr\libraries\Audio
    then copied "effect_gate.h" and "effect_gate.cpp" from https://github.com/macaba/Audio into the "Audio" library folder on my computer.

    Then when using it in code, I made sure to include "#include <effect_gate.h>"

    I hope that helps.

  17. #17
    Senior Member
    Join Date
    Jul 2020
    Posts
    1,364
    I think I'd prefer AudioEffectNoiseGate so its clear what sort of gate it is (for instance CV/gate interface is a thing in modular synthesis).

  18. #18
    Senior Member houtson's Avatar
    Join Date
    Aug 2015
    Location
    Scotland
    Posts
    204
    I made a quick modification to run on Teensy 4.x

    I'm using it as part of a gated reverb so wanted something slightly different from it so it now has two inputs:
    - input 0 is the main audio input that the gain is applied to
    - input 1 is a side chain / control input that is used to activate the gate

    If you are looking to use it just as the original then connect your audio input to both input 0 and input 1.

    Cheers Paul

    effect_gate.h
    Code:
    /* Permission is hereby granted, free of charge, to any person obtaining a copy
     * of this software and associated documentation files (the "Software"), to deal
     * in the Software without restriction, including without limitation the rights
     * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     * copies of the Software, and to permit persons to whom the Software is
     * furnished to do so, subject to the following conditions:
     *
     * The above copyright notice, development funding notice, and this permission
     * notice shall be included in all copies or substantial portions of the Software.
     *
     * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
     * THE SOFTWARE.
     */
    
    #ifndef effect_gate_h_
    #define effect_gate_h_
    
    #include "Arduino.h"
    #include "AudioStream.h"
    
    const int S_Floor = 0;
    const int S_Attack = 1;
    const int S_Hold = 2;
    const int S_Release = 3;
    
    class AudioEffectGate : public AudioStream
    {
    public:
    	AudioEffectGate(void)
    	  : AudioStream(2, inputQueueArray) {
    		  currentGain = 0.0;
    		  thresholdLevelInt = 16384;	//0.5
    		  attackTimeDelta = 1.0f / (50.0f / (1000.0f / (AUDIO_SAMPLE_RATE / AUDIO_BLOCK_SAMPLES)));			//50ms default
    		  holdTimeDelta = 1.0f / (200.0f / (1000.0f / (AUDIO_SAMPLE_RATE / AUDIO_BLOCK_SAMPLES)));			//200ms default
    		  currentHoldTime = 0.0f;
    		  releaseTimeDelta = 1.0f / (200.0f / (1000.0f / (AUDIO_SAMPLE_RATE / AUDIO_BLOCK_SAMPLES)));		//2000ms default
    		  floorGain = 0.0f;
    		  state = S_Floor;
    	  }
    	void threshold(float threshold) {
    		if (threshold > 1.0f) threshold = 1.0f;
    		else if (threshold < 0.0f) threshold = 0.0f;
    		thresholdLevelInt = threshold * 32767.0f;
    	}
    	void attack(float milliseconds) {
    		if(milliseconds <=  0.0f) {
    			milliseconds = 0.01f; 
    		}
    		attackTimeDelta = 1.0f / (milliseconds / (1000.0f / (AUDIO_SAMPLE_RATE / AUDIO_BLOCK_SAMPLES)));
    	}
    	void hold(float milliseconds) {
    		if(milliseconds <=  0.0f) {
    			milliseconds = 0.01f; 
    		}
    		holdTimeDelta = 1.0f / (milliseconds / (1000.0f / (AUDIO_SAMPLE_RATE / AUDIO_BLOCK_SAMPLES)));
    	}
    	void release(float milliseconds) {
    		if(milliseconds <=  0.0f) {
    			milliseconds = 0.01f; 
    		}
    		releaseTimeDelta = 1.0f / (milliseconds / (1000.0f / (AUDIO_SAMPLE_RATE / AUDIO_BLOCK_SAMPLES)));
    	}
    	void floor(float gain) {
    		if(gain < 0.0f)
    			gain = 0.0f;
    		if(gain > 1.0f)
    			gain = 1.0f;
    		floorGain = gain;
    	}
    	using AudioStream::release;
    	virtual void update(void);
    private:
    	audio_block_t *inputQueueArray[2];
    	int16_t thresholdLevelInt;
    	float attackTimeDelta;
    	float holdTimeDelta;
    	float releaseTimeDelta;
    	float floorGain;
    	int32_t state;
    	//Transient variables
    	float currentGain;
    	float currentHoldTime;
    };
    
    #endif
    effect_gate.cpp
    Code:
    /* Permission is hereby granted, free of charge, to any person obtaining a copy
     * of this software and associated documentation files (the "Software"), to deal
     * in the Software without restriction, including without limitation the rights
     * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     * copies of the Software, and to permit persons to whom the Software is
     * furnished to do so, subject to the following conditions:
     *
     * The above copyright notice, development funding notice, and this permission
     * notice shall be included in all copies or substantial portions of the Software.
     *
     * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
     * THE SOFTWARE.
     */
    
    #include "effect_gate.h"
    
    #include "utility/dspinst.h"
    
    #if defined(KINETISK) || (__ARM_ARCH_7EM__)
    #define MULTI_UNITYGAIN 65536
    
    static void applyGain(int16_t *data, int32_t mult) {
      uint32_t *p = (uint32_t *)data;
      const uint32_t *end = (uint32_t *)(data + AUDIO_BLOCK_SAMPLES);
    
      do {
        uint32_t tmp32 = *p;  // read 2 samples from *data
        int32_t val1 = signed_multiply_32x16b(mult, tmp32);
        int32_t val2 = signed_multiply_32x16t(mult, tmp32);
        val1 = signed_saturate_rshift(val1, 16, 0);
        val2 = signed_saturate_rshift(val2, 16, 0);
        *p++ = pack_16b_16b(val2, val1);
      } while (p < end);
    }
    
    #elif defined(KINETISL)
    #define MULTI_UNITYGAIN 256
    
    static void applyGain(int16_t *data, int32_t mult) {
      const int16_t *end = data + AUDIO_BLOCK_SAMPLES;
    
      do {
        int32_t val = *data * mult;
        *data++ = signed_saturate_rshift(val, 16, 0);
      } while (data < end);
    }
    
    #endif
    
    void AudioEffectGate::update(void) {
      audio_block_t *blocka, *blockb;
      uint32_t i;
      int16_t maxAbsSample = 0;
      bool processNextState = true;
      // blocka = audio to be gated
      // blockb = gate control input
    
      blocka = receiveWritable(0);
      blockb = receiveReadOnly(1);
    
      if (!blocka) {
        if (blockb) release(blockb);
        return;
      }
    
      if (!blockb) {
        if (blocka) release(blocka);
        return;
      }
    
      if (thresholdLevelInt > 0) {  // Only process gate if threshold is non-zero
        for (i = 0; i < AUDIO_BLOCK_SAMPLES; i++) {
          if (abs(blockb->data[i]) > maxAbsSample) maxAbsSample = abs(blockb->data[i]);
        }
    
        while (processNextState) {
          processNextState = false;
          switch (state) {
            case S_Floor:
              currentGain = floorGain;
              if (maxAbsSample > thresholdLevelInt) {
                state = S_Attack;
                processNextState = true;
              }
              break;
            case S_Attack:
              currentGain += attackTimeDelta;
              if (currentGain >= 1.0f) {
                currentGain = 1.0f;
                state = S_Hold;
                processNextState = true;
              }
              break;
            case S_Hold:
              currentGain = 1.0f;
              if (maxAbsSample > thresholdLevelInt) break;  // Re-triggered. Also prevents infinite loop.
              currentHoldTime += holdTimeDelta;
              if (currentHoldTime >= 1.0f) {
                currentHoldTime = 0.0f;
                state = S_Release;
                processNextState = true;
              }
              break;
            case S_Release:
              if (maxAbsSample > thresholdLevelInt) {
                state = S_Attack;
                processNextState = true;
                break;  // Re-triggered
              }
              currentGain -= releaseTimeDelta;
              if (currentGain <= floorGain) {
                currentGain = floorGain;
                state = S_Floor;
                processNextState = true;
              }
              break;
          }
        }
    
        if (currentGain != 1.0f) {
    #if defined(KINETISK) || (__ARM_ARCH_7EM__)
          applyGain(blocka->data, currentGain * 65536.0f);
    #elif defined(KINETISL)
          applyGain(blocka->data, currentGain * 256.0f);
    #endif
        }
      }
    
      transmit(blocka);
      release(blocka);
      if (blockb) release(blockb);
    
    }

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •