Merge pull request #11 from max-huster/master

added a NoiseGate-Effect
pull/6/merge
Bob Larkin 3 years ago committed by GitHub
commit ce8930faf8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 180
      AudioEffectNoiseGate_F32.h
  2. 60
      examples/NoiseGate/main.ino

@ -0,0 +1,180 @@
/*
* AudioEffectNoiseGate_F32
*
* Created: Max Huster, Feb 2021
* Purpose: This module mutes the Audio completly, when it's below a given threshold.
*
* This processes a single stream fo audio data (ie, it is mono)
*
* MIT License. use at your own risk.
*/
#ifndef _AudioEffectNoiseGate_F32_h
#define _AudioEffectNoiseGate_F32_h
#include <arm_math.h> //ARM DSP extensions. for speed!
#include <AudioStream_F32.h>
#ifdef NOISEGATE_EXTENDEDINFO
const float minLinear = pow10f(-60 / 20.0f);
#endif
class AudioEffectNoiseGate_F32 : public AudioStream_F32
{
//GUI: inputs:1, outputs:1 //this line used for automatic generation of GUI node
//GUI: shortName:NoiseGate
public:
//constructor
AudioEffectNoiseGate_F32(void) : AudioStream_F32(1, inputQueueArray_f32){};
AudioEffectNoiseGate_F32(const AudioSettings_F32 &settings) : AudioStream_F32(1, inputQueueArray_f32){};
//here's the method that does all the work
void update(void)
{
//Serial.println("AudioEffectNoiseGate_F32: updating."); //for debugging.
audio_block_f32_t *block;
block = AudioStream_F32::receiveWritable_f32();
if (!block)
return;
// create a new audio block for the gain
audio_block_f32_t *gainBlock = AudioStream_F32::allocate_f32();
// calculate the desired gain
calcGain(block, gainBlock);
// smooth the "blocky" gain block
calcSmoothedGain(gainBlock);
#ifdef NOISEGATE_EXTENDEDINFO
float32_t min;
float32_t max;
uint32_t index;
arm_min_f32(gainBlock->data, gainBlock->length, &min, &index);
arm_max_f32(gainBlock->data, gainBlock->length, &max, &index);
_inBetween = min > minLinear && max < (1 - minLinear);
#endif
// multiply it to the input singal
arm_mult_f32(gainBlock->data, block->data, block->data, block->length);
// release gainBlock
AudioStream_F32::release(gainBlock);
//transmit the block and be done
AudioStream_F32::transmit(block);
AudioStream_F32::release(block);
}
void setThreshold(float dbfs)
{
// convert dbFS to linear value to comapre against later
linearThreshold = pow10f(dbfs / 20.0f);
}
void setOpeningTime(float timeInSeconds)
{
openingTimeConst = expf(-1.0f / (timeInSeconds * AUDIO_SAMPLE_RATE));
}
void setClosingTime(float timeInSeconds)
{
closingTimeConst = expf(-1.0f / (timeInSeconds * AUDIO_SAMPLE_RATE));
}
void setHoldTime(float timeInSeconds)
{
holdTimeNumSamples = timeInSeconds * AUDIO_SAMPLE_RATE;
}
#ifdef NOISEGATE_EXTENDEDINFO
bool infoIsOpeningOrClosing()
{
return _inBetween;
}
#endif
bool infoIsOpen()
{
return _isOpenDisplay;
}
private:
float32_t linearThreshold;
float32_t prev_gain_dB = 0;
float32_t openingTimeConst, closingTimeConst;
float lastGainBlockValue = 0;
int32_t counter, holdTimeNumSamples = 0;
audio_block_f32_t *inputQueueArray_f32[1]; //memory pointer for the input to this module
bool falling = false;
bool _isOpen = false;
bool _isOpenDisplay = false;
#ifdef NOISEGATE_EXTENDEDINFO
bool _inBetween = false;
#endif
void calcGain(audio_block_f32_t *input, audio_block_f32_t *gainBlock)
{
_isOpen = false;
for (int i = 0; i < input->length; i++)
{
// take absolute value and compare it to the set threshold
bool isAboveThres = abs(input->data[i]) > linearThreshold;
_isOpen |= isAboveThres;
// if above the threshold set volume to 1 otherwise to 0, we did not account for holdtime
gainBlock->data[i] = isAboveThres ? 1 : 0;
// if we are falling and are above the threshold, the level is not falling
if (falling & isAboveThres)
{
falling = false;
}
// if we have a falling signal
if (falling || lastGainBlockValue > gainBlock->data[i])
{
// check whether the hold time is not reached
if (counter < holdTimeNumSamples)
{
// signal is (still) falling
falling = true;
counter++;
gainBlock->data[i] = 1.0f;
}
// otherwise the signal is already muted due to the line: "gainBlock->data[i] = isAboveThres ? 1 : 0;"
}
// note the last gain value, so we can compare it if the signal is falling in the next sample
lastGainBlockValue = gainBlock->data[i];
}
// note the display value
_isOpenDisplay = _isOpen;
};
//this method applies the "opening" and "closing" constants to smooth the
//target gain level through time.
void calcSmoothedGain(audio_block_f32_t *gain_block)
{
float32_t gain;
float32_t one_minus_opening_const = 1.0f - openingTimeConst;
float32_t one_minus_closing_const = 1.0f - closingTimeConst;
for (int i = 0; i < gain_block->length; i++)
{
gain = gain_block->data[i];
//smooth the gain using the opening or closing constants
if (gain < prev_gain_dB)
{ //are we in the opening phase?
gain_block->data[i] = openingTimeConst * prev_gain_dB + one_minus_opening_const * gain;
}
else
{ //or, we're in the closing phase
gain_block->data[i] = closingTimeConst * prev_gain_dB + one_minus_closing_const * gain;
}
//save value for the next time through this loop
prev_gain_dB = gain_block->data[i];
}
//return
return; //the output here is gain_block
}
};
#endif

@ -0,0 +1,60 @@
#include <Audio.h>
// the next line can be skipped if more perfomance is needed
#define NOISEGATE_EXTENDEDINFO
#include <OpenAudio_ArduinoLibrary.h>
#include <Arduino.h>
AudioInputI2S_F32 i2sAudioIn1;
AudioOutputI2S_F32 i2sAudioOut1;
AudioEffectNoiseGate_F32 noiseGate;
AudioConnection_F32 patchCordL1(i2sAudioIn1, 0, noiseGate, 0);
AudioConnection_F32 patchCordL2(noiseGate, 0, i2sAudioOut1, 0);
AudioConnection_F32 patchCordR1(i2sAudioIn1, 1, i2sAudioOut1, 1);
#define LED_RED 0
#define LED_YELLOW 1
#define LED_GREEN 2
//The setup function is called once when the system starts up
void setup(void)
{
//Start the USB serial link (to enable debugging)
Serial.begin(115200);
delay(500);
Serial.println("Setup starting...");
//Allocate dynamically shuffled memory for the audio subsystem
AudioMemory(20);
AudioMemory_F32(20);
//Put your own setup code here
pinMode(LED_RED, OUTPUT);
pinMode(LED_GREEN, OUTPUT);
pinMode(LED_YELLOW, OUTPUT);
// setup the noise gate. it is probaly a good idea to filter the incoming signal @20 Hz, maybe this colud be added in the future
noiseGate.setOpeningTime(0.02f);
noiseGate.setClosingTime(0.05f);
noiseGate.setHoldTime(0.1);
noiseGate.setThreshold(-40);
//End of setup
Serial.println("Setup complete.");
};
//After setup(), the loop function loops forever.
//Note that the audio modules are called in the background.
//They do not need to be serviced by the loop() function.
float lastVal = 0;
void loop(void)
{
bool thresTrigger = noiseGate.infoIsOpen();
digitalWrite(LED_RED, !thresTrigger);
digitalWrite(LED_GREEN, thresTrigger);
digitalWrite(LED_YELLOW, noiseGate.infoIsOpeningOrClosing());
};
Loading…
Cancel
Save