From 7a5ec429d19509b51856142ab65f8936c387d1a5 Mon Sep 17 00:00:00 2001 From: Craig Hansen-Sturm Date: Sat, 6 Sep 2014 02:29:48 -0700 Subject: [PATCH] audio rendering loop now uses input-gain, tone-generator, noise-generator, and post-generator-gain objects / audiobuffer object now shared between all new audio objects / zero buffer copy between new objects / inline tone-generator code removed / new audio options for generators --- interface/src/Audio.cpp | 82 ++++++++++++++++++++++++++++------------- interface/src/Audio.h | 36 +++++++++++++++--- 2 files changed, 88 insertions(+), 30 deletions(-) diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 8a788df831..3c13d3825d 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -40,6 +40,7 @@ #include #include "Audio.h" + #include "Menu.h" #include "Util.h" #include "PositionalAudioStream.h" @@ -82,7 +83,7 @@ Audio::Audio(QObject* parent) : _noiseGateSampleCounter(0), _noiseGateOpen(false), _noiseGateEnabled(true), - _toneInjectionEnabled(false), + _audioSourceInjectEnabled(false), _noiseGateFramesToClose(0), _totalInputAudioSamples(0), _collisionSoundMagnitude(0.0f), @@ -102,6 +103,8 @@ Audio::Audio(QObject* parent) : _framesPerScope(DEFAULT_FRAMES_PER_SCOPE), _samplesPerScope(NETWORK_SAMPLES_PER_FRAME * _framesPerScope), _peqEnabled(false), + _noiseSourceEnabled(false), + _toneSourceEnabled(true), _scopeInput(0), _scopeOutputLeft(0), _scopeOutputRight(0), @@ -137,6 +140,10 @@ void Audio::reset() { _receivedAudioStream.reset(); resetStats(); _peq.reset(); + _noiseSource.reset(); + _toneSource.reset(); + _sourceGain.reset(); + _inputGain.reset(); } void Audio::resetStats() { @@ -424,14 +431,25 @@ void Audio::start() { qDebug() << "Unable to set up audio output because of a problem with output format."; } - _peq.initialize( _inputFormat.sampleRate(), _audioInput->bufferSize() ); - + _inputFrameBuffer.initialize( _inputFormat.channelCount(), _audioInput->bufferSize() * 2 ); + _peq.initialize( _inputFormat.sampleRate() ); + _inputGain.initialize(); + _sourceGain.initialize(); + _noiseSource.initialize(); + _toneSource.initialize(); + _sourceGain.setParameters(0.25f,0.0f); + _inputGain.setParameters(1.0f,0.0f); } void Audio::stop() { + _inputFrameBuffer.finalize(); _peq.finalize(); - + _inputGain.finalize(); + _sourceGain.finalize(); + _noiseSource.finalize(); + _toneSource.finalize(); + // "switch" to invalid devices in order to shut down the state switchInputToAudioDevice(QAudioDeviceInfo()); switchOutputToAudioDevice(QAudioDeviceInfo()); @@ -477,14 +495,30 @@ void Audio::handleAudioInput() { QByteArray inputByteArray = _inputDevice->readAll(); + int16_t* inputBuffer = (int16_t*)inputByteArray.data(); + const int inputFrameCount = inputByteArray.size() / sizeof(int16_t); + + _inputFrameBuffer.copyFrames(1, inputFrameCount, inputBuffer, false /*copy in*/); + + _inputGain.render(_inputFrameBuffer); // input/mic gain+mute + + // Add audio source injection if enabled + if (_audioSourceInjectEnabled && !_muted) { + + if (_toneSourceEnabled) { // sine generator + _toneSource.render(_inputFrameBuffer); + } + else if(_noiseSourceEnabled) { // pink noise generator + _noiseSource.render(_inputFrameBuffer); + } + _sourceGain.render(_inputFrameBuffer); // post gain + } if (_peqEnabled && !_muted) { - // we wish to pre-filter our captured input, prior to loopback - - int16_t* ioBuffer = (int16_t*)inputByteArray.data(); - - _peq.render(ioBuffer, ioBuffer, inputByteArray.size() / sizeof(int16_t)); + _peq.render(_inputFrameBuffer); // 3-band parametric eq } + _inputFrameBuffer.copyFrames(1, inputFrameCount, inputBuffer, true /*copy out*/); + if (Menu::getInstance()->isOptionChecked(MenuOption::EchoLocalAudio) && !_muted && _audioOutput) { // if this person wants local loopback add that to the locally injected audio @@ -522,7 +556,7 @@ void Audio::handleAudioInput() { int16_t* inputAudioSamples = new int16_t[inputSamplesRequired]; _inputRingBuffer.readSamples(inputAudioSamples, inputSamplesRequired); - + const int numNetworkBytes = _isStereoInput ? NETWORK_BUFFER_LENGTH_BYTES_STEREO : NETWORK_BUFFER_LENGTH_BYTES_PER_CHANNEL; const int numNetworkSamples = _isStereoInput ? NETWORK_BUFFER_LENGTH_SAMPLES_STEREO : NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL; @@ -599,20 +633,8 @@ void Audio::handleAudioInput() { _dcOffset = DC_OFFSET_AVERAGING * _dcOffset + (1.0f - DC_OFFSET_AVERAGING) * measuredDcOffset; } - // Add tone injection if enabled - const float TONE_FREQ = 220.0f / SAMPLE_RATE * TWO_PI; - const float QUARTER_VOLUME = 8192.0f; - if (_toneInjectionEnabled) { - loudness = 0.0f; - for (int i = 0; i < NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL; i++) { - networkAudioSamples[i] = QUARTER_VOLUME * sinf(TONE_FREQ * (float)(i + _proceduralEffectSample)); - loudness += fabsf(networkAudioSamples[i]); - } - } - _lastInputLoudness = fabs(loudness / NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL); - // If Noise Gate is enabled, check and turn the gate on and off - if (!_toneInjectionEnabled && _noiseGateEnabled) { + if (!_audioSourceInjectEnabled && _noiseGateEnabled) { float averageOfAllSampleFrames = 0.0f; _noiseSampleFrames[_noiseGateSampleCounter++] = _lastInputLoudness; if (_noiseGateSampleCounter == NUMBER_OF_NOISE_SAMPLE_FRAMES) { @@ -1041,8 +1063,18 @@ void Audio::processProceduralAudio(int16_t* monoInput, int numSamples) { } } -void Audio::toggleToneInjection() { - _toneInjectionEnabled = !_toneInjectionEnabled; +void Audio::toggleAudioSourceInject() { + _audioSourceInjectEnabled = !_audioSourceInjectEnabled; +} + +void Audio::selectAudioSourcePinkNoise() { + _noiseSourceEnabled = Menu::getInstance()->isOptionChecked(MenuOption::AudioSourcePinkNoise); + _toneSourceEnabled = !_noiseSourceEnabled; +} + +void Audio::selectAudioSourceSine440() { + _toneSourceEnabled = Menu::getInstance()->isOptionChecked(MenuOption::AudioSourceSine440); + _noiseSourceEnabled = !_toneSourceEnabled; } void Audio::toggleAudioSpatialProcessing() { diff --git a/interface/src/Audio.h b/interface/src/Audio.h index b5069f3b3a..f73e0331de 100644 --- a/interface/src/Audio.h +++ b/interface/src/Audio.h @@ -20,6 +20,12 @@ #include "Recorder.h" #include "RingBufferHistory.h" #include "MovingMinMaxAvg.h" +#include "AudioRingBuffer.h" +#include "AudioFormat.h" +#include "AudioBuffer.h" +#include "AudioSourceTone.h" +#include "AudioSourceNoise.h" +#include "AudioGain.h" #include "AudioFilter.h" #include "AudioFilterBank.h" @@ -116,7 +122,9 @@ public slots: void audioMixerKilled(); void toggleMute(); void toggleAudioNoiseReduction(); - void toggleToneInjection(); + void toggleAudioSourceInject(); + void selectAudioSourcePinkNoise(); + void selectAudioSourceSine440(); void toggleScope(); void toggleScopePause(); void toggleStats(); @@ -199,7 +207,8 @@ private: int _noiseGateSampleCounter; bool _noiseGateOpen; bool _noiseGateEnabled; - bool _toneInjectionEnabled; + bool _audioSourceInjectEnabled; + int _noiseGateFramesToClose; int _totalInputAudioSamples; @@ -282,10 +291,27 @@ private: int _framesPerScope; int _samplesPerScope; - // Multi-band parametric EQ - bool _peqEnabled; - AudioFilterPEQ3m _peq; + // Input framebuffer + AudioBufferFloat32 _inputFrameBuffer; + + // Input gain + AudioGain _inputGain; + + // Post tone/pink noise generator gain + AudioGain _sourceGain; + // Pink noise source + bool _noiseSourceEnabled; + AudioSourcePinkNoise _noiseSource; + + // Tone source + bool _toneSourceEnabled; + AudioSourceTone _toneSource; + + // Multi-band parametric EQ + bool _peqEnabled; + AudioFilterPEQ3m _peq; + QMutex _guard; QByteArray* _scopeInput; QByteArray* _scopeOutputLeft;