mirror of
https://github.com/overte-org/overte.git
synced 2025-04-21 19:04:32 +02:00
Merge pull request #3368 from chansensturm/audio-noise
New Audio Buffer, Format, Tone Generator, Pink Noise Generator, and Gain objects
This commit is contained in:
commit
8068117f0c
15 changed files with 687 additions and 42 deletions
|
@ -40,6 +40,7 @@
|
|||
#include <glm/glm.hpp>
|
||||
|
||||
#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* inputFrameData = (int16_t*)inputByteArray.data();
|
||||
const int inputFrameCount = inputByteArray.size() / sizeof(int16_t);
|
||||
|
||||
_inputFrameBuffer.copyFrames(1, inputFrameCount, inputFrameData, 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, 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
|
||||
|
||||
|
@ -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() {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -545,11 +545,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(),
|
||||
|
|
|
@ -347,7 +347,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";
|
||||
|
|
174
libraries/audio/src/AudioBuffer.h
Normal file
174
libraries/audio/src/AudioBuffer.h
Normal file
|
@ -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 <typeinfo>
|
||||
|
||||
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) {
|
||||
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
|
||||
|
|
@ -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.);
|
||||
}
|
||||
|
||||
|
|
|
@ -9,9 +9,12 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
#include <SharedUtil.h>
|
||||
#include "AudioRingBuffer.h"
|
||||
#include "AudioFormat.h"
|
||||
#include "AudioBuffer.h"
|
||||
#include "AudioFilter.h"
|
||||
#include "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;
|
||||
}
|
||||
|
@ -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,16 @@ 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) {
|
||||
|
|
85
libraries/audio/src/AudioFormat.h
Normal file
85
libraries/audio/src/AudioFormat.h
Normal file
|
@ -0,0 +1,85 @@
|
|||
//
|
||||
// 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 (currently for 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() {
|
||||
memset(this, 0, sizeof(*this));
|
||||
}
|
||||
~AudioFormat() { }
|
||||
|
||||
AudioFormat& operator=(const AudioFormat& fmt) {
|
||||
memcpy(this, &fmt, sizeof(*this));
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator==(const AudioFormat& fmt) {
|
||||
return memcmp(this, &fmt, sizeof(*this)) == 0;
|
||||
}
|
||||
|
||||
bool operator!=(const AudioFormat& fmt) {
|
||||
return memcmp(this, &fmt, sizeof(*this)) != 0;
|
||||
}
|
||||
|
||||
void setCanonicalFloat32(uint32_t channels) {
|
||||
assert(channels > 0 && channels <= 2);
|
||||
_sampleRate = SAMPLE_RATE; // todo: create audio constants header
|
||||
_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; // todo: create audio constants header
|
||||
_bitsPerChannel = sizeof(int16_t) * 8;
|
||||
_channelsPerFrame = channels;
|
||||
_bytesPerFrame = _channelsPerFrame * _bitsPerChannel / 8;
|
||||
_flags._isSigned = true;
|
||||
_flags._isInterleaved = _channelsPerFrame > 1;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // hifi_AudioFormat_h
|
75
libraries/audio/src/AudioGain.h
Normal file
75
libraries/audio/src/AudioGain.h
Normal file
|
@ -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
|
||||
|
||||
|
21
libraries/audio/src/AudioSourceNoise.cpp
Normal file
21
libraries/audio/src/AudioSourceNoise.cpp
Normal file
|
@ -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 <assert.h>
|
||||
#include <math.h>
|
||||
#include <SharedUtil.h>
|
||||
#include "AudioRingBuffer.h"
|
||||
#include "AudioFormat.h"
|
||||
#include "AudioBuffer.h"
|
||||
#include "AudioSourceNoise.h"
|
||||
|
||||
template<>
|
||||
uint32_t AudioSourcePinkNoise::_randomSeed = 1974; // a truly random number
|
103
libraries/audio/src/AudioSourceNoise.h
Normal file
103
libraries/audio/src/AudioSourceNoise.h
Normal file
|
@ -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() {
|
||||
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
|
||||
|
20
libraries/audio/src/AudioSourceTone.cpp
Normal file
20
libraries/audio/src/AudioSourceTone.cpp
Normal file
|
@ -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 <assert.h>
|
||||
#include <math.h>
|
||||
#include <SharedUtil.h>
|
||||
#include "AudioRingBuffer.h"
|
||||
#include "AudioFormat.h"
|
||||
#include "AudioBuffer.h"
|
||||
#include "AudioSourceTone.h"
|
||||
|
||||
uint32_t AudioSourceTone::_frameOffset = 0;
|
72
libraries/audio/src/AudioSourceTone.h
Normal file
72
libraries/audio/src/AudioSourceTone.h
Normal file
|
@ -0,0 +1,72 @@
|
|||
//
|
||||
// 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 _amplitude;
|
||||
float32_t _sampleRate;
|
||||
float32_t _omega;
|
||||
|
||||
public:
|
||||
AudioSourceTone() {
|
||||
initialize();
|
||||
}
|
||||
|
||||
~AudioSourceTone() {
|
||||
finalize();
|
||||
}
|
||||
|
||||
void initialize() {
|
||||
_frameOffset = 0;
|
||||
setParameters(SAMPLE_RATE, 220.0f, 0.9f);
|
||||
}
|
||||
|
||||
void finalize() {
|
||||
}
|
||||
|
||||
void reset() {
|
||||
_frameOffset = 0;
|
||||
}
|
||||
|
||||
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, float32_t& amplitude) {
|
||||
sampleRate = _sampleRate;
|
||||
frequency = _frequency;
|
||||
amplitude = _amplitude;
|
||||
}
|
||||
|
||||
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
|
||||
|
|
@ -16,6 +16,8 @@
|
|||
#include <AABox.h>
|
||||
|
||||
#include "InboundAudioStream.h"
|
||||
#include "AudioFormat.h"
|
||||
#include "AudioBuffer.h"
|
||||
#include "AudioFilter.h"
|
||||
#include "AudioFilterBank.h"
|
||||
|
||||
|
|
Loading…
Reference in a new issue