This commit is contained in:
Philip Rosedale 2014-09-15 20:00:49 -07:00
commit ca556d7eb3
6 changed files with 141 additions and 82 deletions

View file

@ -321,9 +321,14 @@ int AudioMixer::addStreamToMixForListeningNodeWithStream(PositionalAudioStream*
const float TWO_OVER_PI = 2.0f / PI;
const float ZERO_DB = 1.0f;
const float NEGATIVE_ONE_DB = 0.891f;
// const float NEGATIVE_ONE_DB = 0.891f;
const float NEGATIVE_THREE_DB = 0.708f;
const float NEGATIVE_SIX_DB = 0.501f;
const float FILTER_GAIN_AT_0 = ZERO_DB; // source is in front
const float FILTER_GAIN_AT_90 = NEGATIVE_SIX_DB; // source is incident to left or right ear
const float FILTER_GAIN_AT_180 = NEGATIVE_SIX_DB; // source is behind
const float FILTER_CUTOFF_FREQUENCY_HZ = 1000.0f;
const float penumbraFilterFrequency = FILTER_CUTOFF_FREQUENCY_HZ; // constant frequency
@ -334,32 +339,25 @@ int AudioMixer::addStreamToMixForListeningNodeWithStream(PositionalAudioStream*
// variable gain calculation broken down by quadrent
if (bearingAngleToSource < -PI_OVER_TWO && bearingAngleToSource > -PI) {
// gainL(-pi/2,0b)->(-pi,-1db)
penumbraFilterGainL = TWO_OVER_PI *
(ZERO_DB - NEGATIVE_ONE_DB) * (bearingAngleToSource + PI_OVER_TWO) + ZERO_DB;
// gainR(-pi/2,-3db)->(-pi,-1db)
(FILTER_GAIN_AT_0 - FILTER_GAIN_AT_180) * (bearingAngleToSource + PI_OVER_TWO) + FILTER_GAIN_AT_0;
penumbraFilterGainR = TWO_OVER_PI *
(NEGATIVE_THREE_DB - NEGATIVE_ONE_DB) * (bearingAngleToSource + PI_OVER_TWO) + NEGATIVE_THREE_DB;
(FILTER_GAIN_AT_90 - FILTER_GAIN_AT_180) * (bearingAngleToSource + PI_OVER_TWO) + FILTER_GAIN_AT_90;
} else if (bearingAngleToSource <= PI && bearingAngleToSource > PI_OVER_TWO) {
// gainL(+pi,-1db)->(pi/2,-3db)
penumbraFilterGainL = TWO_OVER_PI *
(NEGATIVE_ONE_DB - NEGATIVE_THREE_DB) * (bearingAngleToSource - PI) + NEGATIVE_ONE_DB;
// gainR(+pi,-1db)->(pi/2,0db)
(FILTER_GAIN_AT_180 - FILTER_GAIN_AT_90) * (bearingAngleToSource - PI) + FILTER_GAIN_AT_180;
penumbraFilterGainR = TWO_OVER_PI *
(NEGATIVE_ONE_DB - ZERO_DB) * (bearingAngleToSource - PI) + NEGATIVE_ONE_DB;
(FILTER_GAIN_AT_180 - FILTER_GAIN_AT_0) * (bearingAngleToSource - PI) + FILTER_GAIN_AT_180;
} else if (bearingAngleToSource <= PI_OVER_TWO && bearingAngleToSource > 0) {
// gainL(+pi/2,-3db)->(0,0db)
penumbraFilterGainL = TWO_OVER_PI *
(NEGATIVE_THREE_DB - ZERO_DB) * (bearingAngleToSource - PI_OVER_TWO) + NEGATIVE_THREE_DB;
// gainR(+p1/2,0db)->(0,0db)
penumbraFilterGainR = ZERO_DB;
(FILTER_GAIN_AT_90 - FILTER_GAIN_AT_0) * (bearingAngleToSource - PI_OVER_TWO) + FILTER_GAIN_AT_90;
penumbraFilterGainR = FILTER_GAIN_AT_0;
} else {
// gainL(0,0db)->(-pi/2,0db)
penumbraFilterGainL = ZERO_DB;
// gainR(0,0db)->(-pi/2,-3db)
penumbraFilterGainL = FILTER_GAIN_AT_0;
penumbraFilterGainR = TWO_OVER_PI *
(ZERO_DB - NEGATIVE_THREE_DB) * (bearingAngleToSource) + ZERO_DB;
(FILTER_GAIN_AT_0 - FILTER_GAIN_AT_90) * (bearingAngleToSource) + FILTER_GAIN_AT_0;
}
#if 0
qDebug() << "avatar="
<< listeningNodeStream

View file

@ -67,7 +67,7 @@
"type": "checkbox",
"label": "Enable Positional Filter",
"help": "If enabled, positional audio stream uses lowpass filter",
"default": false
"default": true
}
}
}

View file

@ -0,0 +1,27 @@
//
// loadScriptFromMessage.js
// examples
//
// Created by Thijs Wenker on 9/15/14.
// Copyright 2014 High Fidelity, Inc.
//
// Filters script links out of incomming messages and prompts you to run the script.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
//Javascript link RegEX
const JS_LINK_REGEX = /https?:\/\/[^ ]+\.js/i;
function onIncomingMessage(user, message) {
var script_link = JS_LINK_REGEX.exec(message);
if (script_link == null) {
return;
}
if (Window.confirm("@" + user + " sent the following script:\n" + script_link + "\nwould you like to run it?")) {
Script.load(script_link);
}
}
GlobalServices.incomingMessage.connect(onIncomingMessage);

View file

@ -506,30 +506,34 @@ void Audio::handleAudioInput() {
QByteArray inputByteArray = _inputDevice->readAll();
int16_t* inputFrameData = (int16_t*)inputByteArray.data();
const int inputFrameCount = inputByteArray.size() / sizeof(int16_t);
if (!_muted && (_audioSourceInjectEnabled || _peqEnabled)) {
int16_t* inputFrameData = (int16_t*)inputByteArray.data();
const int inputFrameCount = inputByteArray.size() / sizeof(int16_t);
_inputFrameBuffer.copyFrames(1, inputFrameCount, inputFrameData, false /*copy in*/);
_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);
#if ENABLE_INPUT_GAIN
_inputGain.render(_inputFrameBuffer); // input/mic gain+mute
#endif
// Add audio source injection if enabled
if (_audioSourceInjectEnabled) {
if (_toneSourceEnabled) { // sine generator
_toneSource.render(_inputFrameBuffer);
}
else if(_noiseSourceEnabled) { // pink noise generator
_noiseSource.render(_inputFrameBuffer);
}
_sourceGain.render(_inputFrameBuffer); // post gain
}
else if(_noiseSourceEnabled) { // pink noise generator
_noiseSource.render(_inputFrameBuffer);
if (_peqEnabled) {
_peq.render(_inputFrameBuffer); // 3-band parametric eq
}
_sourceGain.render(_inputFrameBuffer); // post gain
}
if (_peqEnabled && !_muted) {
_peq.render(_inputFrameBuffer); // 3-band parametric eq
}
_inputFrameBuffer.copyFrames(1, inputFrameCount, inputFrameData, 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

View file

@ -17,4 +17,43 @@
#include "AudioBuffer.h"
#include "AudioSourceTone.h"
uint32_t AudioSourceTone::_frameOffset = 0;
AudioSourceTone::AudioSourceTone() {
initialize();
}
AudioSourceTone::~AudioSourceTone() {
finalize();
}
void AudioSourceTone::finalize() {
}
void AudioSourceTone::reset() {
}
void AudioSourceTone::updateCoefficients() {
_omega = _frequency / _sampleRate * TWO_PI;
_epsilon = 2.0f * sinf(_omega / 2.0f);
_yq1 = cosf(-1.0f * _omega);
_y1 = sinf(+1.0f * _omega);
}
void AudioSourceTone::initialize() {
const float32_t FREQUENCY_220_HZ = 220.0f;
const float32_t GAIN_MINUS_3DB = 0.708f;
setParameters(SAMPLE_RATE, FREQUENCY_220_HZ, GAIN_MINUS_3DB);
}
void AudioSourceTone::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);
updateCoefficients();
}
void AudioSourceTone::getParameters(float32_t& sampleRate, float32_t& frequency, float32_t& amplitude) {
sampleRate = _sampleRate;
frequency = _frequency;
amplitude = _amplitude;
}

View file

@ -12,61 +12,52 @@
#ifndef hifi_AudioSourceTone_h
#define hifi_AudioSourceTone_h
// Implements a two-pole Gordon-Smith oscillator
class AudioSourceTone
{
static uint32_t _frameOffset;
float32_t _frequency;
float32_t _amplitude;
float32_t _sampleRate;
float32_t _omega;
float32_t _epsilon;
float32_t _yq1;
float32_t _y1;
void updateCoefficients();
public:
AudioSourceTone() {
initialize();
}
AudioSourceTone();
~AudioSourceTone();
~AudioSourceTone() {
finalize();
}
void initialize() {
_frameOffset = 0;
setParameters(SAMPLE_RATE, 220.0f, 0.9f);
}
void finalize() {
}
void reset() {
_frameOffset = 0;
}
void initialize();
void finalize();
void reset();
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 setParameters(const float32_t sampleRate, const float32_t frequency, const float32_t amplitude);
void getParameters(float32_t& sampleRate, float32_t& frequency, float32_t& amplitude);
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();
}
void render(AudioBufferFloat32& frameBuffer);
};
inline void AudioSourceTone::render(AudioBufferFloat32& frameBuffer) {
float32_t** samples = frameBuffer.getFrameData();
float32_t yq;
float32_t y;
for (uint16_t i = 0; i < frameBuffer.getFrameCount(); ++i) {
yq = _yq1 - (_epsilon * _y1);
y = _y1 + (_epsilon * yq);
// update delays
_yq1 = yq;
_y1 = y;
for (uint16_t j = 0; j < frameBuffer.getChannelCount(); ++j) {
samples[j][i] = _amplitude * y;
}
}
}
#endif