mirror of
https://github.com/overte-org/overte.git
synced 2025-04-20 02:23:57 +02:00
Merge pull request #9872 from ZappoMan/fadeInWhenOpeningNoiseGate
code review changes
This commit is contained in:
commit
a8d18adf83
3 changed files with 68 additions and 62 deletions
|
@ -1028,7 +1028,7 @@ void AudioClient::handleAudioInput() {
|
|||
// if we performed the noise gate we can get values from it instead of enumerating the samples again
|
||||
_lastInputLoudness = _inputGate.getLastLoudness();
|
||||
|
||||
if (_inputGate.clippedInLastFrame()) {
|
||||
if (_inputGate.clippedInLastBlock()) {
|
||||
_timeSinceLastClip = 0.0f;
|
||||
}
|
||||
|
||||
|
@ -1049,10 +1049,9 @@ void AudioClient::handleAudioInput() {
|
|||
|
||||
emit inputReceived({ reinterpret_cast<char*>(networkAudioSamples), numNetworkBytes });
|
||||
|
||||
if (_inputGate.openedInLastFrame()) {
|
||||
if (_inputGate.openedInLastBlock()) {
|
||||
emit noiseGateOpened();
|
||||
}
|
||||
if (_inputGate.closedInLastFrame()) {
|
||||
} else if (_inputGate.closedInLastBlock()) {
|
||||
emit noiseGateClosed();
|
||||
}
|
||||
|
||||
|
@ -1072,7 +1071,7 @@ void AudioClient::handleAudioInput() {
|
|||
// the output from the input gate (eventually, this could be crossfaded)
|
||||
// and allow the codec to properly encode down to silent/zero. If we still
|
||||
// have _lastInputLoudness of 0 in our NEXT frame, we will send a silent packet
|
||||
if (_lastInputLoudness == 0 && !_inputGate.closedInLastFrame()) {
|
||||
if (_lastInputLoudness == 0 && !_inputGate.closedInLastBlock()) {
|
||||
packetType = PacketType::SilentAudioFrame;
|
||||
_silentOutbound.increment();
|
||||
} else {
|
||||
|
|
|
@ -19,16 +19,16 @@
|
|||
const float AudioNoiseGate::CLIPPING_THRESHOLD = 0.90f;
|
||||
|
||||
AudioNoiseGate::AudioNoiseGate() :
|
||||
_inputFrameCounter(0),
|
||||
_inputBlockCounter(0),
|
||||
_lastLoudness(0.0f),
|
||||
_quietestFrame(std::numeric_limits<float>::max()),
|
||||
_loudestFrame(0.0f),
|
||||
_didClipInLastFrame(false),
|
||||
_quietestBlock(std::numeric_limits<float>::max()),
|
||||
_loudestBlock(0.0f),
|
||||
_didClipInLastBlock(false),
|
||||
_dcOffset(0.0f),
|
||||
_measuredFloor(0.0f),
|
||||
_sampleCounter(0),
|
||||
_isOpen(false),
|
||||
_framesToClose(0)
|
||||
_blocksToClose(0)
|
||||
{
|
||||
|
||||
}
|
||||
|
@ -37,7 +37,7 @@ void AudioNoiseGate::removeDCOffset(int16_t* samples, int numSamples) {
|
|||
//
|
||||
// DC Offset correction
|
||||
//
|
||||
// Measure the DC offset over a trailing number of frames, and remove it from the input signal.
|
||||
// Measure the DC offset over a trailing number of blocks, and remove it from the input signal.
|
||||
// This causes the noise background measurements and server muting to be more accurate. Many off-board
|
||||
// ADC's have a noticeable DC offset.
|
||||
//
|
||||
|
@ -51,7 +51,7 @@ void AudioNoiseGate::removeDCOffset(int16_t* samples, int numSamples) {
|
|||
// Update measured DC offset
|
||||
measuredDcOffset /= numSamples;
|
||||
if (_dcOffset == 0.0f) {
|
||||
// On first frame, copy over measured offset
|
||||
// On first block, copy over measured offset
|
||||
_dcOffset = measuredDcOffset;
|
||||
} else {
|
||||
_dcOffset = DC_OFFSET_AVERAGING * _dcOffset + (1.0f - DC_OFFSET_AVERAGING) * measuredDcOffset;
|
||||
|
@ -69,13 +69,13 @@ void AudioNoiseGate::gateSamples(int16_t* samples, int numSamples) {
|
|||
//
|
||||
// NOISE_GATE_HEIGHT: How loud you have to speak relative to noise background to open the gate.
|
||||
// Make this value lower for more sensitivity and less rejection of noise.
|
||||
// NOISE_GATE_WIDTH: The number of samples in an audio frame for which the height must be exceeded
|
||||
// NOISE_GATE_WIDTH: The number of samples in an audio block for which the height must be exceeded
|
||||
// to open the gate.
|
||||
// NOISE_GATE_CLOSE_FRAME_DELAY: Once the noise is below the gate height for the frame, how many frames
|
||||
// NOISE_GATE_CLOSE_BLOCK_DELAY: Once the noise is below the gate height for the block, how many blocks
|
||||
// will we wait before closing the gate.
|
||||
// NOISE_GATE_FRAMES_TO_AVERAGE: How many audio frames should we average together to compute noise floor.
|
||||
// NOISE_GATE_BLOCKS_TO_AVERAGE: How many audio blocks should we average together to compute noise floor.
|
||||
// More means better rejection but also can reject continuous things like singing.
|
||||
// NUMBER_OF_NOISE_SAMPLE_FRAMES: How often should we re-evaluate the noise floor?
|
||||
// NUMBER_OF_NOISE_SAMPLE_BLOCKS: How often should we re-evaluate the noise floor?
|
||||
|
||||
float loudness = 0;
|
||||
int thisSample = 0;
|
||||
|
@ -83,16 +83,16 @@ void AudioNoiseGate::gateSamples(int16_t* samples, int numSamples) {
|
|||
|
||||
const float NOISE_GATE_HEIGHT = 7.0f;
|
||||
const int NOISE_GATE_WIDTH = 5;
|
||||
const int NOISE_GATE_CLOSE_FRAME_DELAY = 5;
|
||||
const int NOISE_GATE_FRAMES_TO_AVERAGE = 5;
|
||||
const int NOISE_GATE_CLOSE_BLOCK_DELAY = 5;
|
||||
const int NOISE_GATE_BLOCKS_TO_AVERAGE = 5;
|
||||
|
||||
// Check clipping, and check if should open noise gate
|
||||
_didClipInLastFrame = false;
|
||||
_didClipInLastBlock = false;
|
||||
|
||||
for (int i = 0; i < numSamples; i++) {
|
||||
thisSample = std::abs(samples[i]);
|
||||
if (thisSample >= ((float) AudioConstants::MAX_SAMPLE_VALUE * CLIPPING_THRESHOLD)) {
|
||||
_didClipInLastFrame = true;
|
||||
_didClipInLastBlock = true;
|
||||
}
|
||||
|
||||
loudness += thisSample;
|
||||
|
@ -104,61 +104,64 @@ void AudioNoiseGate::gateSamples(int16_t* samples, int numSamples) {
|
|||
|
||||
_lastLoudness = fabs(loudness / numSamples);
|
||||
|
||||
if (_quietestFrame > _lastLoudness) {
|
||||
_quietestFrame = _lastLoudness;
|
||||
if (_quietestBlock > _lastLoudness) {
|
||||
_quietestBlock = _lastLoudness;
|
||||
}
|
||||
if (_loudestFrame < _lastLoudness) {
|
||||
_loudestFrame = _lastLoudness;
|
||||
if (_loudestBlock < _lastLoudness) {
|
||||
_loudestBlock = _lastLoudness;
|
||||
}
|
||||
|
||||
const int FRAMES_FOR_NOISE_DETECTION = 400;
|
||||
if (_inputFrameCounter++ > FRAMES_FOR_NOISE_DETECTION) {
|
||||
_quietestFrame = std::numeric_limits<float>::max();
|
||||
_loudestFrame = 0.0f;
|
||||
_inputFrameCounter = 0;
|
||||
if (_inputBlockCounter++ > FRAMES_FOR_NOISE_DETECTION) {
|
||||
_quietestBlock = std::numeric_limits<float>::max();
|
||||
_loudestBlock = 0.0f;
|
||||
_inputBlockCounter = 0;
|
||||
}
|
||||
|
||||
// If Noise Gate is enabled, check and turn the gate on and off
|
||||
float averageOfAllSampleFrames = 0.0f;
|
||||
_sampleFrames[_sampleCounter++] = _lastLoudness;
|
||||
if (_sampleCounter == NUMBER_OF_NOISE_SAMPLE_FRAMES) {
|
||||
float averageOfAllSampleBlocks = 0.0f;
|
||||
_sampleBlocks[_sampleCounter++] = _lastLoudness;
|
||||
if (_sampleCounter == NUMBER_OF_NOISE_SAMPLE_BLOCKS) {
|
||||
float smallestSample = std::numeric_limits<float>::max();
|
||||
for (int i = 0; i <= NUMBER_OF_NOISE_SAMPLE_FRAMES - NOISE_GATE_FRAMES_TO_AVERAGE; i += NOISE_GATE_FRAMES_TO_AVERAGE) {
|
||||
for (int i = 0; i <= NUMBER_OF_NOISE_SAMPLE_BLOCKS - NOISE_GATE_BLOCKS_TO_AVERAGE; i += NOISE_GATE_BLOCKS_TO_AVERAGE) {
|
||||
float thisAverage = 0.0f;
|
||||
for (int j = i; j < i + NOISE_GATE_FRAMES_TO_AVERAGE; j++) {
|
||||
thisAverage += _sampleFrames[j];
|
||||
averageOfAllSampleFrames += _sampleFrames[j];
|
||||
for (int j = i; j < i + NOISE_GATE_BLOCKS_TO_AVERAGE; j++) {
|
||||
thisAverage += _sampleBlocks[j];
|
||||
averageOfAllSampleBlocks += _sampleBlocks[j];
|
||||
}
|
||||
thisAverage /= NOISE_GATE_FRAMES_TO_AVERAGE;
|
||||
thisAverage /= NOISE_GATE_BLOCKS_TO_AVERAGE;
|
||||
|
||||
if (thisAverage < smallestSample) {
|
||||
smallestSample = thisAverage;
|
||||
}
|
||||
}
|
||||
averageOfAllSampleFrames /= NUMBER_OF_NOISE_SAMPLE_FRAMES;
|
||||
averageOfAllSampleBlocks /= NUMBER_OF_NOISE_SAMPLE_BLOCKS;
|
||||
_measuredFloor = smallestSample;
|
||||
_sampleCounter = 0;
|
||||
|
||||
}
|
||||
|
||||
_closedInLastFrame = false;
|
||||
_openedInLastFrame = false;
|
||||
_closedInLastBlock = false;
|
||||
_openedInLastBlock = false;
|
||||
|
||||
if (samplesOverNoiseGate > NOISE_GATE_WIDTH) {
|
||||
_openedInLastFrame = !_isOpen;
|
||||
_openedInLastBlock = !_isOpen;
|
||||
_isOpen = true;
|
||||
_framesToClose = NOISE_GATE_CLOSE_FRAME_DELAY;
|
||||
_blocksToClose = NOISE_GATE_CLOSE_BLOCK_DELAY;
|
||||
} else {
|
||||
if (--_framesToClose == 0) {
|
||||
_closedInLastFrame = _isOpen;
|
||||
if (--_blocksToClose == 0) {
|
||||
_closedInLastBlock = _isOpen;
|
||||
_isOpen = false;
|
||||
}
|
||||
}
|
||||
if (!_isOpen) {
|
||||
if (_closedInLastFrame) {
|
||||
// would be nice to do a little crossfade to silence
|
||||
// First block after being closed gets faded to silence, we fade across
|
||||
// the entire block on fading out. All subsequent blocks are muted by being slammed
|
||||
// to zeros
|
||||
if (_closedInLastBlock) {
|
||||
float fadeSlope = (1.0f / numSamples);
|
||||
for (int i = 0; i < numSamples; i++) {
|
||||
float fadedSample = (1.0f - (float)i / (float)numSamples) * (float)samples[i];
|
||||
float fadedSample = (1.0f - ((float)i * fadeSlope)) * (float)samples[i];
|
||||
samples[i] = (int16_t)fadedSample;
|
||||
}
|
||||
} else {
|
||||
|
@ -167,10 +170,14 @@ void AudioNoiseGate::gateSamples(int16_t* samples, int numSamples) {
|
|||
_lastLoudness = 0;
|
||||
}
|
||||
|
||||
if (_openedInLastFrame) {
|
||||
// would be nice to do a little crossfade from silence
|
||||
for (int i = 0; i < numSamples; i++) {
|
||||
float fadedSample = ((float)i / (float)numSamples) * (float)samples[i];
|
||||
if (_openedInLastBlock) {
|
||||
// would be nice to do a little crossfade from silence, but we only want to fade
|
||||
// across the first 1/10th of the block, because we don't want to miss early
|
||||
// transients.
|
||||
int fadeSamples = numSamples / 10; // fade over 1/10th of the samples
|
||||
float fadeSlope = (1.0f / fadeSamples);
|
||||
for (int i = 0; i < fadeSamples; i++) {
|
||||
float fadedSample = (float)i * fadeSlope * (float)samples[i];
|
||||
samples[i] = (int16_t)fadedSample;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
|
||||
#include <stdint.h>
|
||||
|
||||
const int NUMBER_OF_NOISE_SAMPLE_FRAMES = 300;
|
||||
const int NUMBER_OF_NOISE_SAMPLE_BLOCKS = 300;
|
||||
|
||||
class AudioNoiseGate {
|
||||
public:
|
||||
|
@ -23,9 +23,9 @@ public:
|
|||
void gateSamples(int16_t* samples, int numSamples);
|
||||
void removeDCOffset(int16_t* samples, int numSamples);
|
||||
|
||||
bool clippedInLastFrame() const { return _didClipInLastFrame; }
|
||||
bool closedInLastFrame() const { return _closedInLastFrame; }
|
||||
bool openedInLastFrame() const { return _openedInLastFrame; }
|
||||
bool clippedInLastBlock() const { return _didClipInLastBlock; }
|
||||
bool closedInLastBlock() const { return _closedInLastBlock; }
|
||||
bool openedInLastBlock() const { return _openedInLastBlock; }
|
||||
bool isOpen() const { return _isOpen; }
|
||||
float getMeasuredFloor() const { return _measuredFloor; }
|
||||
float getLastLoudness() const { return _lastLoudness; }
|
||||
|
@ -33,19 +33,19 @@ public:
|
|||
static const float CLIPPING_THRESHOLD;
|
||||
|
||||
private:
|
||||
int _inputFrameCounter;
|
||||
int _inputBlockCounter;
|
||||
float _lastLoudness;
|
||||
float _quietestFrame;
|
||||
float _loudestFrame;
|
||||
bool _didClipInLastFrame;
|
||||
float _quietestBlock;
|
||||
float _loudestBlock;
|
||||
bool _didClipInLastBlock;
|
||||
float _dcOffset;
|
||||
float _measuredFloor;
|
||||
float _sampleFrames[NUMBER_OF_NOISE_SAMPLE_FRAMES];
|
||||
float _sampleBlocks[NUMBER_OF_NOISE_SAMPLE_BLOCKS];
|
||||
int _sampleCounter;
|
||||
bool _isOpen;
|
||||
bool _closedInLastFrame { false };
|
||||
bool _openedInLastFrame { false };
|
||||
int _framesToClose;
|
||||
bool _closedInLastBlock { false };
|
||||
bool _openedInLastBlock { false };
|
||||
int _blocksToClose;
|
||||
};
|
||||
|
||||
#endif // hifi_AudioNoiseGate_h
|
Loading…
Reference in a new issue