From 0322c8b9343a1bd84c7db865e656a0fe6ced28b4 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Tue, 11 Feb 2014 23:44:22 -0800 Subject: [PATCH] Added minimum sample counting method for noise reduction --- examples/editVoxels.js | 26 +++++++++++++++--------- interface/src/Audio.cpp | 45 +++++++++++++++++++++++++++++++++++++---- interface/src/Audio.h | 2 ++ 3 files changed, 60 insertions(+), 13 deletions(-) diff --git a/examples/editVoxels.js b/examples/editVoxels.js index cf7736c5bc..62ce968180 100644 --- a/examples/editVoxels.js +++ b/examples/editVoxels.js @@ -65,10 +65,10 @@ var numColors = 8; var whichColor = -1; // Starting color is 'Copy' mode // Create sounds for adding, deleting, recoloring voxels -var addSound = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Electronic/ElectronicBurst1.raw"); -var deleteSound = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Bubbles/bubbles1.raw"); +var addSound = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Switches+and+sliders/slider+-+whoosh1.raw"); +var deleteSound = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Switches+and+sliders/slider+-+whoosh2.raw"); var changeColorSound = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Electronic/ElectronicBurst6.raw"); -var clickSound = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Collisions-ballhitsandcatches/ballcatch2.raw"); +var clickSound = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Switches+and+sliders/toggle+switch+-+medium.raw"); var audioOptions = new AudioInjectionOptions();
 audioOptions.volume = 0.5; @@ -94,18 +94,18 @@ function mousePressEvent(event) { if (intersection.intersects) { if (event.isAlt) { // start orbit camera! + var cameraPosition = Camera.getPosition(); oldMode = Camera.getMode(); Camera.setMode("independent"); isOrbiting = true; Camera.keepLookingAt(intersection.intersection); // get position for initial azimuth, elevation orbitCenter = intersection.intersection; - var cameraPosition = Camera.getPosition(); var orbitVector = Vec3.subtract(cameraPosition, orbitCenter); orbitRadius = vLength(orbitVector); - print("Orbit radius = " + orbitRadius); orbitAzimuth = Math.atan(orbitVector.z / orbitVector.x); - orbitAltitude = Math.atan(orbitVector.y / orbitVector.x); + orbitAltitude = Math.atan(orbitVector.y / Math.sqrt(orbitVector.z * orbitVector.z + orbitVector.x * orbitVector.x)); + print("start: radius, azimuth, altitude = " + orbitRadius + ", " + orbitAzimuth + ", " + orbitAltitude); } else if (event.isRightButton || event.isControl) { // Delete voxel @@ -210,6 +210,7 @@ function mouseMoveEvent(event) { var dy = event.y - mouseY; orbitAzimuth += dx / ORBIT_RATE_AZIMUTH; orbitAltitude += dy / ORBIT_RATE_ALTITUDE; + print("drag: radius, azimuth, altitude = " + orbitRadius + ", " + orbitAzimuth + ", " + orbitAltitude); //print("Azimuth, Altitude: " + orbitAzimuth + ", " + orbitAltitude); var orbitVector = { x:(Math.cos(orbitAzimuth) * Math.cos(orbitAltitude)) * orbitRadius, y:Math.sin(orbitAltitude) * orbitRadius, @@ -261,11 +262,18 @@ function mouseMoveEvent(event) { } function mouseReleaseEvent(event) { + if (isOrbiting) { + var cameraOrientation = Camera.getOrientation(); + var eulers = Quat.safeEulerAngles(cameraOrientation); + Camera.stopLooking(); + print("pitch, yaw " + eulers.x + ", " + eulers.y); + MyAvatar.headPitch = eulers.x; + MyAvatar.bodyYaw = eulers.y; + MyAvatar.position = Camera.getPosition(); + Camera.setMode(oldMode); + } isAdding = false; isOrbiting = false; - MyAvatar.position = orbitPosition; - Camera.stopLooking(); - Camera.setMode(oldMode); } Controller.mousePressEvent.connect(mousePressEvent); diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 6eee4453d4..22a1444f9f 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -37,6 +37,8 @@ static const short JITTER_BUFFER_SAMPLES = JITTER_BUFFER_LENGTH_MSECS * NUM_AUDI static const float AUDIO_CALLBACK_MSECS = (float) NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL / (float)SAMPLE_RATE * 1000.0; +static const int NUMBER_OF_NOISE_SAMPLE_FRAMES = 100; + // Mute icon configration static const int ICON_SIZE = 24; static const int ICON_LEFT = 0; @@ -66,6 +68,7 @@ Audio::Audio(Oscilloscope* scope, int16_t initialJitterBufferSamples, QObject* p _jitterBufferSamples(initialJitterBufferSamples), _lastInputLoudness(0), _averageInputLoudness(0), + _noiseGateSampleCounter(0), _noiseGateOpen(false), _noiseGateEnabled(true), _noiseGateFramesToClose(0), @@ -82,6 +85,8 @@ Audio::Audio(Oscilloscope* scope, int16_t initialJitterBufferSamples, QObject* p { // clear the array of locally injected samples memset(_localProceduralSamples, 0, NETWORK_BUFFER_LENGTH_BYTES_PER_CHANNEL); + // Create the noise sample array + _noiseSampleFrames = new float[NUMBER_OF_NOISE_SAMPLE_FRAMES]; } void Audio::init(QGLWidget *parent) { @@ -355,9 +360,17 @@ void Audio::handleAudioInput() { float thisSample = 0; int samplesOverNoiseGate = 0; - const float NOISE_GATE_HEIGHT = 3.f; +#define NOISE_MIN_SAMPLE +#ifdef NOISE_MIN_SAMPLE + const float NOISE_GATE_HEIGHT = 12.f; const int NOISE_GATE_WIDTH = 5; - const int NOISE_GATE_CLOSE_FRAME_DELAY = 30; + const int NOISE_GATE_CLOSE_FRAME_DELAY = 5; +#else + const float NOISE_GATE_HEIGHT = 6.f; + const int NOISE_GATE_WIDTH = 5; + const int NOISE_GATE_CLOSE_FRAME_DELAY = 5; +#endif + for (int i = 0; i < NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL; i++) { thisSample = fabsf(monoAudioSamples[i]); @@ -368,8 +381,32 @@ void Audio::handleAudioInput() { } } _lastInputLoudness = loudness / NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL; + //qDebug("%.1f", _lastInputLoudness); + +#ifdef NOISE_MIN_SAMPLE + _noiseSampleFrames[_noiseGateSampleCounter++] = _lastInputLoudness; + if (_noiseGateSampleCounter == NUMBER_OF_NOISE_SAMPLE_FRAMES) { + float smallestSample = MAXFLOAT; + for (int i = 0; i < NUMBER_OF_NOISE_SAMPLE_FRAMES; i++) { + if (_noiseSampleFrames[i] < smallestSample) { + smallestSample = _noiseSampleFrames[i]; + } + } + _averageInputLoudness = smallestSample; + _noiseGateSampleCounter = 0; + qDebug("smallest sample = %.1f", _averageInputLoudness); + } +#else + _noiseGateSampleCounter++; + if (_noiseGateSampleCounter == NUMBER_OF_NOISE_SAMPLE_FRAMES) { + qDebug("average loudness = %.1f", _averageInputLoudness); + _noiseGateSampleCounter = 0; + } + const float LOUDNESS_AVERAGING_FRAMES = 1000.f; // This will be about 10 seconds _averageInputLoudness = (1.f - 1.f / LOUDNESS_AVERAGING_FRAMES) * _averageInputLoudness + (1.f / LOUDNESS_AVERAGING_FRAMES) * _lastInputLoudness; +#endif + if (_noiseGateEnabled) { if (samplesOverNoiseGate > NOISE_GATE_WIDTH) { @@ -487,7 +524,7 @@ void Audio::addReceivedAudioToBuffer(const QByteArray& audioByteArray) { if (!_ringBuffer.isStarved() && _audioOutput->bytesFree() == _audioOutput->bufferSize()) { // we don't have any audio data left in the output buffer // we just starved - qDebug() << "Audio output just starved."; + //qDebug() << "Audio output just starved."; _ringBuffer.setIsStarved(true); _numFramesDisplayStarve = 10; } @@ -505,7 +542,7 @@ void Audio::addReceivedAudioToBuffer(const QByteArray& audioByteArray) { if (!_ringBuffer.isNotStarvedOrHasMinimumSamples(NETWORK_BUFFER_LENGTH_SAMPLES_STEREO + (_jitterBufferSamples * 2))) { // starved and we don't have enough to start, keep waiting - qDebug() << "Buffer is starved and doesn't have enough samples to start. Held back."; + //qDebug() << "Buffer is starved and doesn't have enough samples to start. Held back."; } else { // We are either already playing back, or we have enough audio to start playing back. _ringBuffer.setIsStarved(false); diff --git a/interface/src/Audio.h b/interface/src/Audio.h index 88e2731006..5028024a0c 100644 --- a/interface/src/Audio.h +++ b/interface/src/Audio.h @@ -110,6 +110,8 @@ private: int16_t _jitterBufferSamples; float _lastInputLoudness; float _averageInputLoudness; + float* _noiseSampleFrames; + int _noiseGateSampleCounter; bool _noiseGateOpen; bool _noiseGateEnabled; int _noiseGateFramesToClose;