From 974c88442c7d10479bc61a54493cbd8833d3fc1c Mon Sep 17 00:00:00 2001 From: Craig Hansen-Sturm Date: Fri, 29 Aug 2014 14:36:11 -0700 Subject: [PATCH 01/16] new audio format object --- libraries/audio/src/AudioFormat.h | 84 +++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 libraries/audio/src/AudioFormat.h diff --git a/libraries/audio/src/AudioFormat.h b/libraries/audio/src/AudioFormat.h new file mode 100644 index 0000000000..0ded25d0c3 --- /dev/null +++ b/libraries/audio/src/AudioFormat.h @@ -0,0 +1,84 @@ +// +// AudioFormat.h +// hifi +// +// Created by Craig Hansen-Sturm on 8/28/14. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_AudioFormat_h +#define hifi_AudioFormat_h + +#ifndef _FLOAT32_T +#define _FLOAT32_T +typedef float float32_t; +#endif + +#ifndef _FLOAT64_T +#define _FLOAT64_T +typedef double float64_t; +#endif + +// +// Audio format structure (uncompressed streams only) +// + +struct AudioFormat { + + struct Flags { + uint32_t _isFloat : 1; + uint32_t _isSigned : 1; + uint32_t _isInterleaved : 1; + uint32_t _isBigEndian : 1; + uint32_t _isPacked : 1; + uint32_t _reserved : 27; + } _flags; + + uint32_t _bytesPerFrame; + uint32_t _channelsPerFrame; + uint32_t _bitsPerChannel; + float64_t _sampleRate; + + AudioFormat() { + std::memset(this, 0, sizeof(*this)); + } + ~AudioFormat() { } + + AudioFormat& operator=(const AudioFormat& fmt) { + std::memcpy(this, &fmt, sizeof(*this)); + return *this; + } + + bool operator==(const AudioFormat& fmt) { + return std::memcmp(this, &fmt, sizeof(*this)) == 0; + } + + bool operator!=(const AudioFormat& fmt) { + return std::memcmp(this, &fmt, sizeof(*this)) != 0; + } + + void setCanonicalFloat32(uint32_t channels) { + assert(channels > 0 && channels <= 2); + _sampleRate = SAMPLE_RATE; + _bitsPerChannel = sizeof(float32_t) * 8; + _channelsPerFrame = channels; + _bytesPerFrame = _channelsPerFrame * _bitsPerChannel / 8; + _flags._isFloat = true; + _flags._isInterleaved = _channelsPerFrame > 1; + } + + void setCanonicalInt16(uint32_t channels) { + assert(channels > 0 && channels <= 2); + _sampleRate = SAMPLE_RATE; + _bitsPerChannel = sizeof(int16_t) * 8; + _channelsPerFrame = channels; + _bytesPerFrame = _channelsPerFrame * _bitsPerChannel / 8; + _flags._isSigned = true; + _flags._isInterleaved = _channelsPerFrame > 1; + } +}; + +#endif // hifi_AudioFormat_h From 68fa44f845aa5b45c851079f47eb7bf050101d5a Mon Sep 17 00:00:00 2001 From: Craig Hansen-Sturm Date: Fri, 5 Sep 2014 18:30:39 -0700 Subject: [PATCH 02/16] audio menu changes to support tone and noise generators --- interface/src/Menu.cpp | 24 ++++++++++++++++++++++-- interface/src/Menu.h | 4 +++- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 0dcfd60051..c2620c1e46 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -544,11 +544,31 @@ Menu::Menu() : 0, this, SLOT(muteEnvironment())); - addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::AudioToneInjection, + + addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::AudioSourceInject, 0, false, appInstance->getAudio(), - SLOT(toggleToneInjection())); + SLOT(toggleAudioSourceInject())); + QMenu* audioSourceMenu = audioDebugMenu->addMenu("Generated Audio Source"); + { + QAction *pinkNoise = addCheckableActionToQMenuAndActionHash(audioSourceMenu, MenuOption::AudioSourcePinkNoise, + 0, + false, + appInstance->getAudio(), + SLOT(selectAudioSourcePinkNoise())); + + QAction *sine440 = addCheckableActionToQMenuAndActionHash(audioSourceMenu, MenuOption::AudioSourceSine440, + 0, + true, + appInstance->getAudio(), + SLOT(selectAudioSourceSine440)); + + QActionGroup* audioSourceGroup = new QActionGroup(audioSourceMenu); + audioSourceGroup->addAction(pinkNoise); + audioSourceGroup->addAction(sine440); + } + addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::AudioScope, Qt::CTRL | Qt::Key_P, false, appInstance->getAudio(), diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 1d57da2891..a00da23b7b 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -346,7 +346,9 @@ namespace MenuOption { const QString AudioSpatialProcessingSlightlyRandomSurfaces = "Slightly Random Surfaces"; const QString AudioSpatialProcessingStereoSource = "Stereo Source"; const QString AudioSpatialProcessingWithDiffusions = "With Diffusions"; - const QString AudioToneInjection = "Inject Test Tone"; + const QString AudioSourceInject = "Generated Audio"; + const QString AudioSourcePinkNoise = "Pink Noise"; + const QString AudioSourceSine440 = "Sine 440hz"; const QString Avatars = "Avatars"; const QString AvatarsReceiveShadows = "Avatars Receive Shadows"; const QString Bandwidth = "Bandwidth Display"; From c6911274f610c2f2e7da903d7827f3ca61ecdf3e Mon Sep 17 00:00:00 2001 From: Craig Hansen-Sturm Date: Sat, 6 Sep 2014 02:14:47 -0700 Subject: [PATCH 03/16] new tone generator audio source object --- libraries/audio/src/AudioSourceTone.cpp | 20 +++++++ libraries/audio/src/AudioSourceTone.h | 69 +++++++++++++++++++++++++ 2 files changed, 89 insertions(+) create mode 100644 libraries/audio/src/AudioSourceTone.cpp create mode 100644 libraries/audio/src/AudioSourceTone.h diff --git a/libraries/audio/src/AudioSourceTone.cpp b/libraries/audio/src/AudioSourceTone.cpp new file mode 100644 index 0000000000..80a6aed48e --- /dev/null +++ b/libraries/audio/src/AudioSourceTone.cpp @@ -0,0 +1,20 @@ +// +// AudioSourceTone.cpp +// hifi +// +// Created by Craig Hansen-Sturm on 8/10/14. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include +#include +#include +#include "AudioRingBuffer.h" +#include "AudioFormat.h" +#include "AudioBuffer.h" +#include "AudioSourceTone.h" + +uint32_t AudioSourceTone::_frameOffset = 0; diff --git a/libraries/audio/src/AudioSourceTone.h b/libraries/audio/src/AudioSourceTone.h new file mode 100644 index 0000000000..fb9d6be0fe --- /dev/null +++ b/libraries/audio/src/AudioSourceTone.h @@ -0,0 +1,69 @@ +// +// AudioSourceTone.h +// hifi +// +// Created by Craig Hansen-Sturm on 9/1/14. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_AudioSourceTone_h +#define hifi_AudioSourceTone_h + +class AudioSourceTone +{ + static uint32_t _frameOffset; + float32_t _frequency; + float32_t _sampleRate; + float32_t _omega; + +public: + AudioSourceTone() { + initialize(); + } + + ~AudioSourceTone() { + finalize(); + } + + void initialize() { + _frameOffset = 0; + setParameters(SAMPLE_RATE, 220.0f); + } + + void finalize() { + } + + void reset() { + _frameOffset = 0; + } + + void setParameters(const float32_t sampleRate, const float32_t frequency) { + _sampleRate = std::max(sampleRate, 1.0f); + _frequency = std::max(frequency, 1.0f); + _omega = _frequency / _sampleRate * TWO_PI; + } + + void getParameters(float32_t& sampleRate, float32_t& frequency) { + sampleRate = _sampleRate; + frequency = _frequency; + } + + void render(AudioBufferFloat32& frameBuffer) { + + // note: this is a placeholder implementation. final version will not include any transcendental ops in our render loop + + float32_t** samples = frameBuffer.getFrameData(); + for (uint16_t i = 0; i < frameBuffer.getFrameCount(); ++i) { + for (uint16_t j = 0; j < frameBuffer.getChannelCount(); ++j) { + samples[j][i] = sinf((i + _frameOffset) * _omega); + } + } + _frameOffset += frameBuffer.getFrameCount(); + } +}; + +#endif + From 3a9a4a64024068644068fc069e31fa7bdc552de8 Mon Sep 17 00:00:00 2001 From: Craig Hansen-Sturm Date: Sat, 6 Sep 2014 02:16:00 -0700 Subject: [PATCH 04/16] new pink noise generator audio source object --- libraries/audio/src/AudioSourceNoise.cpp | 21 +++++ libraries/audio/src/AudioSourceNoise.h | 103 +++++++++++++++++++++++ 2 files changed, 124 insertions(+) create mode 100644 libraries/audio/src/AudioSourceNoise.cpp create mode 100644 libraries/audio/src/AudioSourceNoise.h diff --git a/libraries/audio/src/AudioSourceNoise.cpp b/libraries/audio/src/AudioSourceNoise.cpp new file mode 100644 index 0000000000..6cfdf82fd9 --- /dev/null +++ b/libraries/audio/src/AudioSourceNoise.cpp @@ -0,0 +1,21 @@ +// +// AudioSourceNoise.cpp +// hifi +// +// Created by Craig Hansen-Sturm on 8/10/14. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include +#include +#include +#include "AudioRingBuffer.h" +#include "AudioFormat.h" +#include "AudioBuffer.h" +#include "AudioSourceNoise.h" + +template<> +uint32_t AudioSourcePinkNoise::_randomSeed = 1974; // a truly random number diff --git a/libraries/audio/src/AudioSourceNoise.h b/libraries/audio/src/AudioSourceNoise.h new file mode 100644 index 0000000000..88340628e9 --- /dev/null +++ b/libraries/audio/src/AudioSourceNoise.h @@ -0,0 +1,103 @@ +// +// AudioSourceNoise.h +// hifi +// +// Created by Craig Hansen-Sturm on 9/1/14. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +// Adapted from code by Phil Burk http://www.firstpr.com.au/dsp/pink-noise/ +// + +#ifndef hifi_AudioSourceNoise_h +#define hifi_AudioSourceNoise_h + +template< const uint16_t N = 30> +class AudioSourceNoise +{ + static const uint16_t _randomRows = N; + static const uint16_t _randomBits = 24; + static const uint16_t _randomShift = (sizeof(int32_t) * 8) - _randomBits; + + static uint32_t _randomSeed; + + int32_t _rows[_randomRows]; + int32_t _runningSum; // used to optimize summing of generators. + uint16_t _index; // incremented each sample. + uint16_t _indexMask; // index wrapped by ANDing with this mask. + float32_t _scale; // used to scale within range of -1.0 to +1.0 + + static uint32_t generateRandomNumber() { + _randomSeed = (_randomSeed * 196314165) + 907633515; + return _randomSeed >> _randomShift; + } + +public: + AudioSourceNoise() { + initialize(); + } + + ~AudioSourceNoise() { + finalize(); + } + + void initialize() { + std::memset(_rows, 0, _randomRows * sizeof(int32_t)); + + _runningSum = 0; + _index = 0; + _indexMask = (1 << _randomRows) - 1; + _scale = 1.0f / ((_randomRows + 1) * (1 << (_randomBits - 1))); + } + + void finalize() { + } + + void reset() { + initialize(); + } + + void setParameters(void) { + } + + void getParameters(void) { + } + + void render(AudioBufferFloat32& frameBuffer) { + + uint32_t randomNumber; + + float32_t** samples = frameBuffer.getFrameData(); + for (uint16_t i = 0; i < frameBuffer.getFrameCount(); ++i) { + for (uint16_t j = 0; j < frameBuffer.getChannelCount(); ++j) { + + _index = (_index + 1) & _indexMask; // increment and mask index. + if (_index != 0) { // if index is zero, don't update any random values. + + uint32_t numZeros = 0; // determine how many trailing zeros in _index + uint32_t tmp = _index; + while ((tmp & 1) == 0) { + tmp >>= 1; + numZeros++; + } + // replace the indexed _rows random value. subtract and add back to _runningSum instead + // of adding all the random values together. only one value changes each time. + _runningSum -= _rows[numZeros]; + randomNumber = generateRandomNumber(); + _runningSum += randomNumber; + _rows[numZeros] = randomNumber; + } + + // add extra white noise value and scale between -1.0 and +1.0 + samples[j][i] = (_runningSum + generateRandomNumber()) * _scale; + } + } + } +}; + +typedef AudioSourceNoise<> AudioSourcePinkNoise; + +#endif // AudioSourceNoise_h + From f439475f3ce6cfb622edaab5526b86037621cbee Mon Sep 17 00:00:00 2001 From: Craig Hansen-Sturm Date: Sat, 6 Sep 2014 02:18:04 -0700 Subject: [PATCH 05/16] new audio gain/mute object --- libraries/audio/src/AudioGain.h | 75 +++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 libraries/audio/src/AudioGain.h diff --git a/libraries/audio/src/AudioGain.h b/libraries/audio/src/AudioGain.h new file mode 100644 index 0000000000..c2cc64cba5 --- /dev/null +++ b/libraries/audio/src/AudioGain.h @@ -0,0 +1,75 @@ +// +// AudioGain.h +// hifi +// +// Created by Craig Hansen-Sturm on 9/1/14. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_AudioGain_h +#define hifi_AudioGain_h + +class AudioGain +{ + float32_t _gain; + bool _mute; + +public: + AudioGain() { + initialize(); + } + + ~AudioGain() { + finalize(); + } + + void initialize() { + setParameters(1.0f,0.0f); + } + + void finalize() { + } + + void reset() { + initialize(); + } + + void setParameters(const float gain, const float mute) { + _gain = std::min(std::max(gain, 0.0f), 1.0f); + _mute = mute != 0.0f; + + } + + void getParameters(float& gain, float& mute) { + gain = _gain; + mute = _mute ? 1.0f : 0.0f; + } + + void render(AudioBufferFloat32& frameBuffer) { + if (_mute) { + frameBuffer.zeroFrames(); + return; + } + + float32_t** samples = frameBuffer.getFrameData(); + for (uint16_t j = 0; j < frameBuffer.getChannelCount(); ++j) { + for (uint16_t i = 0; i < frameBuffer.getFrameCount(); i += 8) { + samples[j][i + 0] *= _gain; + samples[j][i + 1] *= _gain; + samples[j][i + 2] *= _gain; + samples[j][i + 3] *= _gain; + samples[j][i + 4] *= _gain; + samples[j][i + 5] *= _gain; + samples[j][i + 6] *= _gain; + samples[j][i + 7] *= _gain; + } + } + } +}; + +#endif // AudioGain_h + + From 0b33c344fffbcc83eaf55bc6e5010549297b0dd0 Mon Sep 17 00:00:00 2001 From: Craig Hansen-Sturm Date: Sat, 6 Sep 2014 02:18:35 -0700 Subject: [PATCH 06/16] new audio buffer object --- libraries/audio/src/AudioBuffer.h | 174 ++++++++++++++++++++++++++++++ 1 file changed, 174 insertions(+) create mode 100644 libraries/audio/src/AudioBuffer.h diff --git a/libraries/audio/src/AudioBuffer.h b/libraries/audio/src/AudioBuffer.h new file mode 100644 index 0000000000..dd0030ecd8 --- /dev/null +++ b/libraries/audio/src/AudioBuffer.h @@ -0,0 +1,174 @@ +// +// AudioBuffer.h +// hifi +// +// Created by Craig Hansen-Sturm on 8/29/14. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_AudioBuffer_h +#define hifi_AudioBuffer_h + +#include + +template< typename T > +class AudioFrameBuffer { + + uint16_t _channelCount; + uint16_t _frameCount; + uint16_t _frameCountMax; + + T** _frameBuffer; + + void allocateFrames() { + _frameBuffer = new T*[_channelCount]; + if (_frameBuffer) { + for (uint16_t i = 0; i < _channelCount; ++i) { + _frameBuffer[i] = new T[_frameCountMax]; + } + } + } + + void deallocateFrames() { + if (_frameBuffer) { + for (uint16_t i = 0; i < _channelCount; ++i) { + delete _frameBuffer[i]; + } + delete _frameBuffer; + } + _frameBuffer = NULL; + } + +public: + + AudioFrameBuffer() + : _channelCount(0) + , _frameCount(0) + , _frameCountMax(0) + , _frameBuffer(NULL) { + } + + AudioFrameBuffer(const uint16_t channelCount, const uint16_t frameCount) + : _channelCount(channelCount) + , _frameCount(frameCount) + , _frameCountMax(frameCount) + , _frameBuffer(NULL) { + allocateFrames(); + } + + ~AudioFrameBuffer() { + finalize(); + } + + void initialize(const uint16_t channelCount, const uint16_t frameCount) { + if (_frameBuffer) { + finalize(); + } + _channelCount = channelCount; + _frameCount = frameCount; + _frameCountMax = frameCount; + allocateFrames(); + } + + void finalize() { + deallocateFrames(); + _channelCount = 0; + _frameCount = 0; + } + + T**& getFrameData() { + return _frameBuffer; + } + + uint16_t getChannelCount() { + return _channelCount; + } + + uint16_t getFrameCount() { + return _frameCount; + } + + void zeroFrames() { + if (!_frameBuffer) { + return; + } + for (uint16_t i = 0; i < _channelCount; ++i) { + std::memset(_frameBuffer[i], 0, sizeof(T)*_frameCountMax); + } + } + + template< typename S > + void copyFrames(uint16_t channelCount, const uint16_t frameCount, S* frames, const bool copyOut = false) { + if ( !_frameBuffer || !frames) { + return; + } + assert(channelCount == _channelCount); + assert(frameCount <= _frameCountMax); + + _frameCount = frameCount; // we allow copying fewer frames than we've allocated + + if (copyOut) { + S* dst = frames; + + if(typeid(T) == typeid(S)) { // source and destination types are the same + for (int i = 0; i < _frameCount; ++i) { + for (int j = 0; j < _channelCount; ++j) { + *dst++ = _frameBuffer[j][i]; + } + } + } + else { + if(typeid(T) == typeid(float32_t) && + typeid(S) == typeid(int16_t)) { + + const int scale = (2 << ((8 * sizeof(S)) - 1)); + + for (int i = 0; i < _frameCount; ++i) { + for (int j = 0; j < _channelCount; ++j) { + *dst++ = (S)(_frameBuffer[j][i] * scale); + } + } + } + else { + assert(0); // currently unsupported conversion + } + } + } + else { // copyIn + S* src = frames; + + if(typeid(T) == typeid(S)) { // source and destination types are the same + for (int i = 0; i < _frameCount; ++i) { + for (int j = 0; j < _channelCount; ++j) { + _frameBuffer[j][i] = *src++; + } + } + } + else { + if(typeid(T) == typeid(float32_t) && + typeid(S) == typeid(int16_t)) { + + const int scale = (2 << ((8 * sizeof(S)) - 1)); + + for (int i = 0; i < _frameCount; ++i) { + for (int j = 0; j < _channelCount; ++j) { + _frameBuffer[j][i] = ((T)(*src++)) / scale; + } + } + } + else { + assert(0); // currently unsupported conversion + } + } + } + } +}; + +typedef AudioFrameBuffer< float32_t > AudioBufferFloat32; +typedef AudioFrameBuffer< int32_t > AudioBufferSInt32; + +#endif // hifi_AudioBuffer_h + From 8ecf0870e7c7ff8325e9835155a9e5417d3e9359 Mon Sep 17 00:00:00 2001 From: Craig Hansen-Sturm Date: Sat, 6 Sep 2014 02:20:14 -0700 Subject: [PATCH 07/16] dependency on new audiobuffer and audioformat objects --- libraries/audio/src/PositionalAudioStream.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libraries/audio/src/PositionalAudioStream.h b/libraries/audio/src/PositionalAudioStream.h index a7f59aebde..f5f1b9027a 100644 --- a/libraries/audio/src/PositionalAudioStream.h +++ b/libraries/audio/src/PositionalAudioStream.h @@ -16,6 +16,8 @@ #include #include "InboundAudioStream.h" +#include "AudioFormat.h" +#include "AudioBuffer.h" #include "AudioFilter.h" #include "AudioFilterBank.h" From 5bab1ee7f58d49d4bea8334afbef7d563b7bc603 Mon Sep 17 00:00:00 2001 From: Craig Hansen-Sturm Date: Sat, 6 Sep 2014 02:22:27 -0700 Subject: [PATCH 08/16] dependency on new audiobuffer and audioformat objects/render call now uses audiobuffers --- libraries/audio/src/AudioFilterBank.cpp | 3 +++ libraries/audio/src/AudioFilterBank.h | 13 ++++++++++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/libraries/audio/src/AudioFilterBank.cpp b/libraries/audio/src/AudioFilterBank.cpp index a7b969540a..6599b29a01 100644 --- a/libraries/audio/src/AudioFilterBank.cpp +++ b/libraries/audio/src/AudioFilterBank.cpp @@ -9,9 +9,12 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include #include #include #include "AudioRingBuffer.h" +#include "AudioFormat.h" +#include "AudioBuffer.h" #include "AudioFilter.h" #include "AudioFilterBank.h" diff --git a/libraries/audio/src/AudioFilterBank.h b/libraries/audio/src/AudioFilterBank.h index c523736a57..2ea29cb3a9 100644 --- a/libraries/audio/src/AudioFilterBank.h +++ b/libraries/audio/src/AudioFilterBank.h @@ -64,7 +64,7 @@ public: // // public interface // - void initialize(const float sampleRate, const int frameCount) { + void initialize(const float sampleRate, const int frameCount = 0) { finalize(); for (int i = 0; i < _channelCount; ++i) { @@ -141,6 +141,17 @@ public: } } + void render(AudioBufferFloat32& frameBuffer) { + + float32_t** samples = frameBuffer.getFrameData(); + for (uint16_t j = 0; j < frameBuffer.getChannelCount(); ++j) { + for (int i = 0; i < _filterCount; ++i) { + _filters[i][j].render( samples[j], samples[j], frameBuffer.getFrameCount() ); + } + } + + } + void reset() { for (int i = 0; i < _filterCount; ++i) { for (int j = 0; j < _channelCount; ++j) { From 7a5ec429d19509b51856142ab65f8936c387d1a5 Mon Sep 17 00:00:00 2001 From: Craig Hansen-Sturm Date: Sat, 6 Sep 2014 02:29:48 -0700 Subject: [PATCH 09/16] 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; From 1eba20bc3bd44feaa208752aa45cd2f6714d4287 Mon Sep 17 00:00:00 2001 From: Craig Hansen-Sturm Date: Sat, 6 Sep 2014 02:32:13 -0700 Subject: [PATCH 10/16] minor cleanup --- libraries/audio/src/AudioFormat.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/audio/src/AudioFormat.h b/libraries/audio/src/AudioFormat.h index 0ded25d0c3..da082ead94 100644 --- a/libraries/audio/src/AudioFormat.h +++ b/libraries/audio/src/AudioFormat.h @@ -23,7 +23,7 @@ typedef double float64_t; #endif // -// Audio format structure (uncompressed streams only) +// Audio format structure (currently for uncompressed streams only) // struct AudioFormat { @@ -62,7 +62,7 @@ struct AudioFormat { void setCanonicalFloat32(uint32_t channels) { assert(channels > 0 && channels <= 2); - _sampleRate = SAMPLE_RATE; + _sampleRate = SAMPLE_RATE; // todo: create audio constants header _bitsPerChannel = sizeof(float32_t) * 8; _channelsPerFrame = channels; _bytesPerFrame = _channelsPerFrame * _bitsPerChannel / 8; @@ -72,7 +72,7 @@ struct AudioFormat { void setCanonicalInt16(uint32_t channels) { assert(channels > 0 && channels <= 2); - _sampleRate = SAMPLE_RATE; + _sampleRate = SAMPLE_RATE; // todo: create audio constants header _bitsPerChannel = sizeof(int16_t) * 8; _channelsPerFrame = channels; _bytesPerFrame = _channelsPerFrame * _bitsPerChannel / 8; From f309875069e0060d99df535e6fcf7a5e7cd7af06 Mon Sep 17 00:00:00 2001 From: Craig Hansen-Sturm Date: Sat, 6 Sep 2014 02:50:37 -0700 Subject: [PATCH 11/16] formatting/renaming --- interface/src/Audio.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 3c13d3825d..0d114b7208 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -495,10 +495,10 @@ void Audio::handleAudioInput() { QByteArray inputByteArray = _inputDevice->readAll(); - int16_t* inputBuffer = (int16_t*)inputByteArray.data(); + int16_t* inputFrameData = (int16_t*)inputByteArray.data(); const int inputFrameCount = inputByteArray.size() / sizeof(int16_t); - _inputFrameBuffer.copyFrames(1, inputFrameCount, inputBuffer, false /*copy in*/); + _inputFrameBuffer.copyFrames(1, inputFrameCount, inputFrameData, false /*copy in*/); _inputGain.render(_inputFrameBuffer); // input/mic gain+mute @@ -517,7 +517,7 @@ void Audio::handleAudioInput() { _peq.render(_inputFrameBuffer); // 3-band parametric eq } - _inputFrameBuffer.copyFrames(1, inputFrameCount, inputBuffer, true /*copy out*/); + _inputFrameBuffer.copyFrames(1, inputFrameCount, inputFrameData, true /*copy out*/); if (Menu::getInstance()->isOptionChecked(MenuOption::EchoLocalAudio) && !_muted && _audioOutput) { // if this person wants local loopback add that to the locally injected audio From e2f3392f09517a5a350b70a75c61772d819b39e3 Mon Sep 17 00:00:00 2001 From: Craig Hansen-Sturm Date: Sat, 6 Sep 2014 02:51:11 -0700 Subject: [PATCH 12/16] formatting/renaming --- libraries/audio/src/AudioFilterBank.h | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/audio/src/AudioFilterBank.h b/libraries/audio/src/AudioFilterBank.h index 2ea29cb3a9..46d781075a 100644 --- a/libraries/audio/src/AudioFilterBank.h +++ b/libraries/audio/src/AudioFilterBank.h @@ -149,7 +149,6 @@ public: _filters[i][j].render( samples[j], samples[j], frameBuffer.getFrameCount() ); } } - } void reset() { From e64c81420e0c0da2fd40cb6d68963b0e2bca2b81 Mon Sep 17 00:00:00 2001 From: Craig Hansen-Sturm Date: Sat, 6 Sep 2014 03:29:14 -0700 Subject: [PATCH 13/16] ubuntu build fix (remove std::memset ...) --- libraries/audio/src/AudioFormat.h | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/libraries/audio/src/AudioFormat.h b/libraries/audio/src/AudioFormat.h index da082ead94..9548138f58 100644 --- a/libraries/audio/src/AudioFormat.h +++ b/libraries/audio/src/AudioFormat.h @@ -42,22 +42,23 @@ struct AudioFormat { uint32_t _bitsPerChannel; float64_t _sampleRate; + AudioFormat() { - std::memset(this, 0, sizeof(*this)); + memset(this, 0, sizeof(*this)); } ~AudioFormat() { } AudioFormat& operator=(const AudioFormat& fmt) { - std::memcpy(this, &fmt, sizeof(*this)); + memcpy(this, &fmt, sizeof(*this)); return *this; } bool operator==(const AudioFormat& fmt) { - return std::memcmp(this, &fmt, sizeof(*this)) == 0; + return memcmp(this, &fmt, sizeof(*this)) == 0; } bool operator!=(const AudioFormat& fmt) { - return std::memcmp(this, &fmt, sizeof(*this)) != 0; + return memcmp(this, &fmt, sizeof(*this)) != 0; } void setCanonicalFloat32(uint32_t channels) { From 76adb952a30da1287f5c0e4d9036472d13c3714b Mon Sep 17 00:00:00 2001 From: Craig Hansen-Sturm Date: Sat, 6 Sep 2014 03:57:11 -0700 Subject: [PATCH 14/16] ubuntu build fix (remove std::memset ...) --- libraries/audio/src/AudioBuffer.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/audio/src/AudioBuffer.h b/libraries/audio/src/AudioBuffer.h index dd0030ecd8..7c244f47bf 100644 --- a/libraries/audio/src/AudioBuffer.h +++ b/libraries/audio/src/AudioBuffer.h @@ -96,7 +96,7 @@ public: return; } for (uint16_t i = 0; i < _channelCount; ++i) { - std::memset(_frameBuffer[i], 0, sizeof(T)*_frameCountMax); + memset(_frameBuffer[i], 0, sizeof(T)*_frameCountMax); } } From 2700d8c59d8f76d2427750d9118da86f0e0de51f Mon Sep 17 00:00:00 2001 From: Craig Hansen-Sturm Date: Sat, 6 Sep 2014 04:05:52 -0700 Subject: [PATCH 15/16] ubuntu build fix (remove std::memset ...) --- libraries/audio/src/AudioSourceNoise.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/audio/src/AudioSourceNoise.h b/libraries/audio/src/AudioSourceNoise.h index 88340628e9..26cb21a065 100644 --- a/libraries/audio/src/AudioSourceNoise.h +++ b/libraries/audio/src/AudioSourceNoise.h @@ -44,7 +44,7 @@ public: } void initialize() { - std::memset(_rows, 0, _randomRows * sizeof(int32_t)); + memset(_rows, 0, _randomRows * sizeof(int32_t)); _runningSum = 0; _index = 0; From 431fcbcf6c7ba2eaaed97f690f34d72f83380210 Mon Sep 17 00:00:00 2001 From: Craig Hansen-Sturm Date: Mon, 8 Sep 2014 11:18:14 -0700 Subject: [PATCH 16/16] coding standard / SLOT selectAudioSourceSine440 linkage / tone gen amplitude parameter --- interface/src/Menu.cpp | 2 +- libraries/audio/src/AudioBuffer.h | 20 ++++++++++---------- libraries/audio/src/AudioFilter.h | 10 +++++----- libraries/audio/src/AudioFilterBank.h | 6 +++--- libraries/audio/src/AudioSourceTone.h | 9 ++++++--- 5 files changed, 25 insertions(+), 22 deletions(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 5f6abe9527..c863c098c2 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -563,7 +563,7 @@ Menu::Menu() : 0, true, appInstance->getAudio(), - SLOT(selectAudioSourceSine440)); + SLOT(selectAudioSourceSine440())); QActionGroup* audioSourceGroup = new QActionGroup(audioSourceMenu); audioSourceGroup->addAction(pinkNoise); diff --git a/libraries/audio/src/AudioBuffer.h b/libraries/audio/src/AudioBuffer.h index 7c244f47bf..0644139f80 100644 --- a/libraries/audio/src/AudioBuffer.h +++ b/libraries/audio/src/AudioBuffer.h @@ -44,18 +44,18 @@ class AudioFrameBuffer { public: - AudioFrameBuffer() - : _channelCount(0) - , _frameCount(0) - , _frameCountMax(0) - , _frameBuffer(NULL) { + AudioFrameBuffer() : + _channelCount(0), + _frameCount(0), + _frameCountMax(0), + _frameBuffer(NULL) { } - AudioFrameBuffer(const uint16_t channelCount, const uint16_t frameCount) - : _channelCount(channelCount) - , _frameCount(frameCount) - , _frameCountMax(frameCount) - , _frameBuffer(NULL) { + AudioFrameBuffer(const uint16_t channelCount, const uint16_t frameCount) : + _channelCount(channelCount), + _frameCount(frameCount), + _frameCountMax(frameCount), + _frameBuffer(NULL) { allocateFrames(); } diff --git a/libraries/audio/src/AudioFilter.h b/libraries/audio/src/AudioFilter.h index c2de3860db..c9458f280e 100644 --- a/libraries/audio/src/AudioFilter.h +++ b/libraries/audio/src/AudioFilter.h @@ -37,11 +37,11 @@ public: // // ctor/dtor // - AudioBiquad() - : _xm1(0.) - , _xm2(0.) - , _ym1(0.) - , _ym2(0.) { + AudioBiquad() : + _xm1(0.), + _xm2(0.), + _ym1(0.), + _ym2(0.) { setParameters(0.,0.,0.,0.,0.); } diff --git a/libraries/audio/src/AudioFilterBank.h b/libraries/audio/src/AudioFilterBank.h index 46d781075a..b9546999d9 100644 --- a/libraries/audio/src/AudioFilterBank.h +++ b/libraries/audio/src/AudioFilterBank.h @@ -49,9 +49,9 @@ public: // // ctor/dtor // - AudioFilterBank() - : _sampleRate(0.) - , _frameCount(0) { + AudioFilterBank() : + _sampleRate(0.0f), + _frameCount(0) { for (int i = 0; i < _channelCount; ++i) { _buffer[ i ] = NULL; } diff --git a/libraries/audio/src/AudioSourceTone.h b/libraries/audio/src/AudioSourceTone.h index fb9d6be0fe..5ebe1ba2a9 100644 --- a/libraries/audio/src/AudioSourceTone.h +++ b/libraries/audio/src/AudioSourceTone.h @@ -16,6 +16,7 @@ class AudioSourceTone { static uint32_t _frameOffset; float32_t _frequency; + float32_t _amplitude; float32_t _sampleRate; float32_t _omega; @@ -30,7 +31,7 @@ public: void initialize() { _frameOffset = 0; - setParameters(SAMPLE_RATE, 220.0f); + setParameters(SAMPLE_RATE, 220.0f, 0.9f); } void finalize() { @@ -40,15 +41,17 @@ public: _frameOffset = 0; } - void setParameters(const float32_t sampleRate, const float32_t frequency) { + void setParameters(const float32_t sampleRate, const float32_t frequency, const float32_t amplitude) { _sampleRate = std::max(sampleRate, 1.0f); _frequency = std::max(frequency, 1.0f); + _amplitude = std::max(amplitude, 1.0f); _omega = _frequency / _sampleRate * TWO_PI; } - void getParameters(float32_t& sampleRate, float32_t& frequency) { + void getParameters(float32_t& sampleRate, float32_t& frequency, float32_t& amplitude) { sampleRate = _sampleRate; frequency = _frequency; + amplitude = _amplitude; } void render(AudioBufferFloat32& frameBuffer) {