From 65121aefb678758d521e404820f459ba44760752 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Mon, 10 Feb 2014 16:42:05 -0800 Subject: [PATCH 1/8] EditVoxels.js: Added color changing with number keys, better audio --- examples/editVoxels.js | 52 +++++++++++++++++++++++++++++++++--------- 1 file changed, 41 insertions(+), 11 deletions(-) diff --git a/examples/editVoxels.js b/examples/editVoxels.js index 96bb09e6d6..7210a07e1b 100644 --- a/examples/editVoxels.js +++ b/examples/editVoxels.js @@ -7,9 +7,10 @@ // // Captures mouse clicks and edits voxels accordingly. // -// click = create a new voxel on this face, same color as old -// Alt + click = delete this voxel +// click = create a new voxel on this face, same color as old (default color picker state) +// right click or control + click = delete this voxel // shift + click = recolor this voxel +// 1 - 8 = pick new color from palette // // Click and drag to create more new voxels in the same direction // @@ -18,6 +19,11 @@ function vLength(v) { return Math.sqrt(v.x * v.x + v.y * v.y + v.z * v.z); } +function vMinus(a, b) { + var rval = { x: a.x - b.x, y: a.y - b.y, z: a.z - b.z }; + return rval; +} + var key_alt = false; var key_shift = false; var isAdding = false; @@ -37,31 +43,32 @@ colors[4] = { red: 193, green: 99, blue: 122 }; colors[5] = { red: 255, green: 54, blue: 69 }; colors[6] = { red: 124, green: 36, blue: 36 }; colors[7] = { red: 63, green: 35, blue: 19 }; -var numColors = 6; -var whichColor = 0; +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 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 audioOptions = new AudioInjectionOptions();
 +audioOptions.volume = 0.5; function mousePressEvent(event) { var pickRay = Camera.computePickRay(event.x, event.y); var intersection = Voxels.findRayIntersection(pickRay); - audioOptions.volume = 1.0; - audioOptions.position = { x: intersection.voxel.x, y: intersection.voxel.y, z: intersection.voxel.z }; + audioOptions.position = { x: pickRay.origin.x + pickRay.direction.x, + y: pickRay.origin.y + pickRay.direction.y, + z: pickRay.origin.z + pickRay.direction.z }; if (intersection.intersects) { - if (key_alt) { + if (event.isRightButton || event.isControl) { // Delete voxel Voxels.eraseVoxel(intersection.voxel.x, intersection.voxel.y, intersection.voxel.z, intersection.voxel.s); Audio.playSound(deleteSound, audioOptions); - } else if (key_shift) { + } else if (event.isShifted) { // Recolor Voxel - whichColor++; - if (whichColor == numColors) whichColor = 0; Voxels.setVoxel(intersection.voxel.x, intersection.voxel.y, intersection.voxel.z, @@ -70,7 +77,9 @@ function mousePressEvent(event) { Audio.playSound(changeColorSound, audioOptions); } else { // Add voxel on face - var newVoxel = { + if (whichColor == -1) { + // Copy mode - use clicked voxel color + var newVoxel = { x: intersection.voxel.x, y: intersection.voxel.y, z: intersection.voxel.z, @@ -78,6 +87,16 @@ function mousePressEvent(event) { red: intersection.voxel.red, green: intersection.voxel.green, blue: intersection.voxel.blue }; + } else { + var newVoxel = { + x: intersection.voxel.x, + y: intersection.voxel.y, + z: intersection.voxel.z, + s: intersection.voxel.s, + red: colors[whichColor].red, + green: colors[whichColor].green, + blue: colors[whichColor].blue }; + } if (intersection.face == "MIN_X_FACE") { newVoxel.x -= newVoxel.s; @@ -108,7 +127,18 @@ function mousePressEvent(event) { function keyPressEvent(event) { key_alt = event.isAlt; key_shift = event.isShifted; + var nVal = parseInt(event.text); + if (event.text == "0") { + print("Color = Copy"); + whichColor = -1; + Audio.playSound(clickSound, audioOptions); + } else if ((nVal > 0) && (nVal <= numColors)) { + whichColor = nVal - 1; + print("Color = " + (whichColor + 1)); + Audio.playSound(clickSound, audioOptions); + } } + function keyReleaseEvent(event) { key_alt = false; key_shift = false; From 49292a478e92435e5baa672d318ed55a4940a891 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Mon, 10 Feb 2014 17:28:24 -0800 Subject: [PATCH 2/8] =?UTF-8?q?EditVoxels.js:=20Added=20new=20voxel=20maki?= =?UTF-8?q?ng=20in=20front=20of=20camera=20with=20=E2=80=989=E2=80=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- examples/editVoxels.js | 37 ++++++++++++++++++++++++++++++++++--- 1 file changed, 34 insertions(+), 3 deletions(-) diff --git a/examples/editVoxels.js b/examples/editVoxels.js index 7210a07e1b..81f5e09ddd 100644 --- a/examples/editVoxels.js +++ b/examples/editVoxels.js @@ -11,6 +11,7 @@ // right click or control + click = delete this voxel // shift + click = recolor this voxel // 1 - 8 = pick new color from palette +// 9 = create a new voxel in front of the camera // // Click and drag to create more new voxels in the same direction // @@ -24,6 +25,9 @@ function vMinus(a, b) { return rval; } +var NEW_VOXEL_SIZE = 1.0; +var NEW_VOXEL_DISTANCE_FROM_CAMERA = 3.0; + var key_alt = false; var key_shift = false; var isAdding = false; @@ -54,12 +58,23 @@ var clickSound = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-publ var audioOptions = new AudioInjectionOptions();
 audioOptions.volume = 0.5; +function setAudioPosition() { + var camera = Camera.getPosition(); + var forwardVector = Quat.getFront(MyAvatar.orientation); + audioOptions.position = Vec3.sum(camera, forwardVector); +} + +function getNewVoxelPosition() { + var camera = Camera.getPosition(); + var forwardVector = Quat.getFront(MyAvatar.orientation); + var newPosition = Vec3.sum(camera, Vec3.multiply(forwardVector, NEW_VOXEL_DISTANCE_FROM_CAMERA)); + return newPosition; +} + function mousePressEvent(event) { var pickRay = Camera.computePickRay(event.x, event.y); var intersection = Voxels.findRayIntersection(pickRay); - audioOptions.position = { x: pickRay.origin.x + pickRay.direction.x, - y: pickRay.origin.y + pickRay.direction.y, - z: pickRay.origin.z + pickRay.direction.z }; + audioOptions.position = Vec3.sum(pickRay.origin, pickRay.direction); if (intersection.intersects) { if (event.isRightButton || event.isControl) { @@ -136,6 +151,22 @@ function keyPressEvent(event) { whichColor = nVal - 1; print("Color = " + (whichColor + 1)); Audio.playSound(clickSound, audioOptions); + } else if (event.text == "9") { + // Create a brand new 1 meter voxel in front of your avatar + var color = whichColor; + if (color == -1) color = 0; + var newPosition = getNewVoxelPosition(); + var newVoxel = { + x: newPosition.x, + y: newPosition.y , + z: newPosition.z, + s: NEW_VOXEL_SIZE, + red: colors[color].red, + green: colors[color].green, + blue: colors[color].blue }; + Voxels.setVoxel(newVoxel.x, newVoxel.y, newVoxel.z, newVoxel.s, newVoxel.red, newVoxel.green, newVoxel.blue); + setAudioPosition(); + Audio.playSound(addSound, audioOptions); } } From b6edd7be7bb27302daba61b8b549b2c57ec641c3 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Tue, 11 Feb 2014 15:07:25 -0800 Subject: [PATCH 3/8] add Vec3::subtract in JS --- examples/editVoxels.js | 52 ++++++++++++++++++++++++++-- libraries/script-engine/src/Vec3.cpp | 4 +++ libraries/script-engine/src/Vec3.h | 1 + 3 files changed, 55 insertions(+), 2 deletions(-) diff --git a/examples/editVoxels.js b/examples/editVoxels.js index 81f5e09ddd..cf7736c5bc 100644 --- a/examples/editVoxels.js +++ b/examples/editVoxels.js @@ -27,16 +27,30 @@ function vMinus(a, b) { var NEW_VOXEL_SIZE = 1.0; var NEW_VOXEL_DISTANCE_FROM_CAMERA = 3.0; +var ORBIT_RATE_ALTITUDE = 100.0; +var ORBIT_RATE_AZIMUTH = 60.0; + +var oldMode = Camera.getMode(); var key_alt = false; var key_shift = false; var isAdding = false; +var isOrbiting = false; +var orbitAzimuth = 0.0; +var orbitAltitude = 0.0; +var orbitCenter = { x: 0, y: 0, z: 0 }; +var orbitPosition = { x: 0, y: 0, z: 0 }; +var orbitRadius = 0.0; var lastVoxelPosition = { x: 0, y: 0, z: 0 }; var lastVoxelColor = { red: 0, green: 0, blue: 0 }; var lastVoxelScale = 0; var dragStart = { x: 0, y: 0 }; +var mouseX = 0; +var mouseY = 0; + + // Create a table of the different colors you can choose var colors = new Array(); colors[0] = { red: 237, green: 175, blue: 0 }; @@ -72,12 +86,28 @@ function getNewVoxelPosition() { } function mousePressEvent(event) { + mouseX = event.x; + mouseY = event.y; var pickRay = Camera.computePickRay(event.x, event.y); var intersection = Voxels.findRayIntersection(pickRay); audioOptions.position = Vec3.sum(pickRay.origin, pickRay.direction); - if (intersection.intersects) { - if (event.isRightButton || event.isControl) { + if (event.isAlt) { + // start orbit camera! + 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); + + } else if (event.isRightButton || event.isControl) { // Delete voxel Voxels.eraseVoxel(intersection.voxel.x, intersection.voxel.y, intersection.voxel.z, intersection.voxel.s); Audio.playSound(deleteSound, audioOptions); @@ -175,6 +205,20 @@ function keyReleaseEvent(event) { key_shift = false; } function mouseMoveEvent(event) { + if (isOrbiting) { + var dx = event.x - mouseX; + var dy = event.y - mouseY; + orbitAzimuth += dx / ORBIT_RATE_AZIMUTH; + orbitAltitude += dy / ORBIT_RATE_ALTITUDE; + //print("Azimuth, Altitude: " + orbitAzimuth + ", " + orbitAltitude); + var orbitVector = { x:(Math.cos(orbitAzimuth) * Math.cos(orbitAltitude)) * orbitRadius, + y:Math.sin(orbitAltitude) * orbitRadius, + z:(Math.sin(orbitAzimuth) * Math.cos(orbitAltitude)) * orbitRadius }; + orbitPosition = Vec3.sum(orbitCenter, orbitVector); + Camera.setPosition(orbitPosition); + mouseX = event.x; + mouseY = event.y; + } if (isAdding) { var pickRay = Camera.computePickRay(event.x, event.y); var lastVoxelDistance = { x: pickRay.origin.x - lastVoxelPosition.x, @@ -218,6 +262,10 @@ function mouseMoveEvent(event) { function mouseReleaseEvent(event) { isAdding = false; + isOrbiting = false; + MyAvatar.position = orbitPosition; + Camera.stopLooking(); + Camera.setMode(oldMode); } Controller.mousePressEvent.connect(mousePressEvent); diff --git a/libraries/script-engine/src/Vec3.cpp b/libraries/script-engine/src/Vec3.cpp index 87b1b510a4..6520e62a34 100644 --- a/libraries/script-engine/src/Vec3.cpp +++ b/libraries/script-engine/src/Vec3.cpp @@ -22,3 +22,7 @@ glm::vec3 Vec3::multiply(const glm::vec3& v1, float f) { glm::vec3 Vec3::sum(const glm::vec3& v1, const glm::vec3& v2) { return v1 + v2; } + +glm::vec3 Vec3::subtract(const glm::vec3& v1, const glm::vec3& v2) { + return v1 - v2; +} diff --git a/libraries/script-engine/src/Vec3.h b/libraries/script-engine/src/Vec3.h index 1cc44f3061..c6f05fb6aa 100644 --- a/libraries/script-engine/src/Vec3.h +++ b/libraries/script-engine/src/Vec3.h @@ -24,6 +24,7 @@ public slots: glm::vec3 multiply(const glm::vec3& v1, const glm::vec3& v2); glm::vec3 multiply(const glm::vec3& v1, float f); glm::vec3 sum(const glm::vec3& v1, const glm::vec3& v2); + glm::vec3 subtract(const glm::vec3& v1, const glm::vec3& v2); }; From 0322c8b9343a1bd84c7db865e656a0fe6ced28b4 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Tue, 11 Feb 2014 23:44:22 -0800 Subject: [PATCH 4/8] 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; From 3a807c1914077ce74ce5ad766b2acc18470b82e5 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Wed, 12 Feb 2014 17:57:52 -0800 Subject: [PATCH 5/8] comment out debugging spam, improved EditVoxels --- examples/editVoxels.js | 124 +++++++++++++++++++++++----------------- interface/src/Audio.cpp | 2 +- 2 files changed, 73 insertions(+), 53 deletions(-) diff --git a/examples/editVoxels.js b/examples/editVoxels.js index 62ce968180..c1f0c8dc49 100644 --- a/examples/editVoxels.js +++ b/examples/editVoxels.js @@ -27,21 +27,24 @@ function vMinus(a, b) { var NEW_VOXEL_SIZE = 1.0; var NEW_VOXEL_DISTANCE_FROM_CAMERA = 3.0; -var ORBIT_RATE_ALTITUDE = 100.0; -var ORBIT_RATE_AZIMUTH = 60.0; +var ORBIT_RATE_ALTITUDE = 200.0; +var ORBIT_RATE_AZIMUTH = 90.0; +var PIXELS_PER_EXTRUDE_VOXEL = 16; var oldMode = Camera.getMode(); var key_alt = false; var key_shift = false; var isAdding = false; +var isExtruding = false; var isOrbiting = false; var orbitAzimuth = 0.0; var orbitAltitude = 0.0; var orbitCenter = { x: 0, y: 0, z: 0 }; var orbitPosition = { x: 0, y: 0, z: 0 }; var orbitRadius = 0.0; - +var extrudeDirection = { x: 0, y: 0, z: 0 }; +var extrudeScale = 0.0; var lastVoxelPosition = { x: 0, y: 0, z: 0 }; var lastVoxelColor = { red: 0, green: 0, blue: 0 }; var lastVoxelScale = 0; @@ -51,6 +54,7 @@ var mouseX = 0; var mouseY = 0; + // Create a table of the different colors you can choose var colors = new Array(); colors[0] = { red: 237, green: 175, blue: 0 }; @@ -65,9 +69,9 @@ 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/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 addSound = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Voxels/voxel+create.raw"); +var deleteSound = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Voxels/voxel+delete.raw"); +var changeColorSound = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Voxels/voxel+edit.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; @@ -85,6 +89,18 @@ function getNewVoxelPosition() { return newPosition; } +function fixEulerAngles(eulers) { + var rVal = { x: 0, y: 0, z: eulers.z }; + if (eulers.x >= 90.0) { + rVal.x = 180.0 - eulers.x; + rVal.y = eulers.y - 180.0; + } else if (eulers.x <= -90.0) { + rVal.x = 180.0 - eulers.x; + rVal.y = eulers.y - 180.0; + } + return rVal; +} + function mousePressEvent(event) { mouseX = event.x; mouseY = event.y; @@ -102,10 +118,9 @@ function mousePressEvent(event) { // get position for initial azimuth, elevation orbitCenter = intersection.intersection; var orbitVector = Vec3.subtract(cameraPosition, orbitCenter); - orbitRadius = vLength(orbitVector); - orbitAzimuth = Math.atan(orbitVector.z / 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); + orbitRadius = vLength(orbitVector); + orbitAzimuth = Math.atan2(orbitVector.z, orbitVector.x); + orbitAltitude = Math.asin(orbitVector.y / Vec3.length(orbitVector)); } else if (event.isRightButton || event.isControl) { // Delete voxel @@ -197,6 +212,11 @@ function keyPressEvent(event) { Voxels.setVoxel(newVoxel.x, newVoxel.y, newVoxel.z, newVoxel.s, newVoxel.red, newVoxel.green, newVoxel.blue); setAudioPosition(); Audio.playSound(addSound, audioOptions); + } else if (event.text == " ") { + // Reset my orientation! + var orientation = { x:0, y:0, z:0, w:1 }; + Camera.setOrientation(orientation); + MyAvatar.orientation = orientation; } } @@ -206,57 +226,57 @@ function keyReleaseEvent(event) { } function mouseMoveEvent(event) { if (isOrbiting) { + var cameraOrientation = Camera.getOrientation(); + var origEulers = Quat.safeEulerAngles(cameraOrientation); + var newEulers = fixEulerAngles(Quat.safeEulerAngles(cameraOrientation)); var dx = event.x - mouseX; 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, + var orbitVector = { x:(Math.cos(orbitAltitude) * Math.cos(orbitAzimuth)) * orbitRadius, y:Math.sin(orbitAltitude) * orbitRadius, - z:(Math.sin(orbitAzimuth) * Math.cos(orbitAltitude)) * orbitRadius }; + z:(Math.cos(orbitAltitude) * Math.sin(orbitAzimuth)) * orbitRadius }; orbitPosition = Vec3.sum(orbitCenter, orbitVector); Camera.setPosition(orbitPosition); mouseX = event.x; mouseY = event.y; } if (isAdding) { - var pickRay = Camera.computePickRay(event.x, event.y); - var lastVoxelDistance = { x: pickRay.origin.x - lastVoxelPosition.x, + // Watch the drag direction to tell which way to 'extrude' this voxel + if (!isExtruding) { + var pickRay = Camera.computePickRay(event.x, event.y); + var lastVoxelDistance = { x: pickRay.origin.x - lastVoxelPosition.x, y: pickRay.origin.y - lastVoxelPosition.y, z: pickRay.origin.z - lastVoxelPosition.z }; - var distance = vLength(lastVoxelDistance); - var mouseSpot = { x: pickRay.direction.x * distance, y: pickRay.direction.y * distance, z: pickRay.direction.z * distance }; - mouseSpot.x += pickRay.origin.x; - mouseSpot.y += pickRay.origin.y; - mouseSpot.z += pickRay.origin.z; - var dx = mouseSpot.x - lastVoxelPosition.x; - var dy = mouseSpot.y - lastVoxelPosition.y; - var dz = mouseSpot.z - lastVoxelPosition.z; - if (dx > lastVoxelScale) { - lastVoxelPosition.x += lastVoxelScale; - Voxels.setVoxel(lastVoxelPosition.x, lastVoxelPosition.y, lastVoxelPosition.z, - lastVoxelScale, lastVoxelColor.red, lastVoxelColor.green, lastVoxelColor.blue); - } else if (dx < -lastVoxelScale) { - lastVoxelPosition.x -= lastVoxelScale; - Voxels.setVoxel(lastVoxelPosition.x, lastVoxelPosition.y, lastVoxelPosition.z, - lastVoxelScale, lastVoxelColor.red, lastVoxelColor.green, lastVoxelColor.blue); - } else if (dy > lastVoxelScale) { - lastVoxelPosition.y += lastVoxelScale; - Voxels.setVoxel(lastVoxelPosition.x, lastVoxelPosition.y, lastVoxelPosition.z, - lastVoxelScale, lastVoxelColor.red, lastVoxelColor.green, lastVoxelColor.blue); - } else if (dy < -lastVoxelScale) { - lastVoxelPosition.y -= lastVoxelScale; - Voxels.setVoxel(lastVoxelPosition.x, lastVoxelPosition.y, lastVoxelPosition.z, - lastVoxelScale, lastVoxelColor.red, lastVoxelColor.green, lastVoxelColor.blue); - } else if (dz > lastVoxelScale) { - lastVoxelPosition.z += lastVoxelScale; - Voxels.setVoxel(lastVoxelPosition.x, lastVoxelPosition.y, lastVoxelPosition.z, - lastVoxelScale, lastVoxelColor.red, lastVoxelColor.green, lastVoxelColor.blue); - } else if (dz < -lastVoxelScale) { - lastVoxelPosition.z -= lastVoxelScale; - Voxels.setVoxel(lastVoxelPosition.x, lastVoxelPosition.y, lastVoxelPosition.z, - lastVoxelScale, lastVoxelColor.red, lastVoxelColor.green, lastVoxelColor.blue); + var distance = vLength(lastVoxelDistance); + var mouseSpot = { x: pickRay.direction.x * distance, y: pickRay.direction.y * distance, z: pickRay.direction.z * distance }; + mouseSpot.x += pickRay.origin.x; + mouseSpot.y += pickRay.origin.y; + mouseSpot.z += pickRay.origin.z; + var dx = mouseSpot.x - lastVoxelPosition.x; + var dy = mouseSpot.y - lastVoxelPosition.y; + var dz = mouseSpot.z - lastVoxelPosition.z; + extrudeScale = lastVoxelScale; + extrudeDirection = { x: 0, y: 0, z: 0 }; + isExtruding = true; + if (dx > lastVoxelScale) extrudeDirection.x = extrudeScale; + else if (dx < -lastVoxelScale) extrudeDirection.x = -extrudeScale; + else if (dy > lastVoxelScale) extrudeDirection.y = extrudeScale; + else if (dy < -lastVoxelScale) extrudeDirection.y = -extrudeScale; + else if (dz > lastVoxelScale) extrudeDirection.z = extrudeScale; + else if (dz < -lastVoxelScale) extrudeDirection.z = -extrudeScale; + else isExtruding = false; + } else { + // We have got an extrusion direction, now look for mouse move beyond threshold to add new voxel + var dx = event.x - mouseX; + var dy = event.y - mouseY; + if (Math.sqrt(dx*dx + dy*dy) > PIXELS_PER_EXTRUDE_VOXEL) { + lastVoxelPosition = Vec3.sum(lastVoxelPosition, extrudeDirection); + Voxels.setVoxel(lastVoxelPosition.x, lastVoxelPosition.y, lastVoxelPosition.z, + extrudeScale, lastVoxelColor.red, lastVoxelColor.green, lastVoxelColor.blue); + mouseX = event.x; + mouseY = event.y; + } } } } @@ -265,15 +285,15 @@ 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(); + MyAvatar.orientation = cameraOrientation; + Camera.stopLooking(); Camera.setMode(oldMode); + Camera.setOrientation(cameraOrientation); } isAdding = false; isOrbiting = false; + isExtruding = false; } Controller.mousePressEvent.connect(mousePressEvent); diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 22a1444f9f..76da290591 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -394,7 +394,7 @@ void Audio::handleAudioInput() { } _averageInputLoudness = smallestSample; _noiseGateSampleCounter = 0; - qDebug("smallest sample = %.1f", _averageInputLoudness); + //qDebug("smallest sample = %.1f", _averageInputLoudness); } #else _noiseGateSampleCounter++; From be7d1a57236c846510aaf4e09d97f969b7089277 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Wed, 12 Feb 2014 22:53:46 -0800 Subject: [PATCH 6/8] Adjustments to noise gate, commit to min sampling method --- interface/src/Audio.cpp | 70 +++++++++++++++++++++++------------------ interface/src/Audio.h | 4 +-- 2 files changed, 41 insertions(+), 33 deletions(-) diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 76da290591..30352639c0 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -37,7 +37,7 @@ 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; +static const int NUMBER_OF_NOISE_SAMPLE_FRAMES = 300; // Mute icon configration static const int ICON_SIZE = 24; @@ -67,7 +67,7 @@ Audio::Audio(Oscilloscope* scope, int16_t initialJitterBufferSamples, QObject* p _measuredJitter(0), _jitterBufferSamples(initialJitterBufferSamples), _lastInputLoudness(0), - _averageInputLoudness(0), + _noiseGateMeasuredFloor(0), _noiseGateSampleCounter(0), _noiseGateOpen(false), _noiseGateEnabled(true), @@ -356,58 +356,66 @@ void Audio::handleAudioInput() { NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL, _inputFormat, _desiredInputFormat); + // + // Impose Noise Gate + // + // The Noise Gate is used to reject constant background noise by measuring the noise + // floor observed at the microphone and then opening the 'gate' to allow microphone + // signals to be transmitted when the microphone samples average level exceeds a multiple + // of the noise floor. + // + // NOISE_GATE_HEIGHT: How loud you have to speak relative to noise background to open the gate. + // Make this value lower for more sensitivity and less rejection of noise. + // NOISE_GATE_WIDTH: The number of samples in an audio frame for which the height must be exceeded + // to open the gate. + // NOISE_GATE_CLOSE_FRAME_DELAY: Once the noise is below the gate height for the frame, how many frames + // will we wait before closing the gate. + // NOISE_GATE_FRAMES_TO_AVERAGE: How many audio frames should we average together to compute noise floor. + // More means better rejection but also can reject continuous things like singing. + // NUMBER_OF_NOISE_SAMPLE_FRAMES: How often should we re-evaluate the noise floor? + + float loudness = 0; float thisSample = 0; int samplesOverNoiseGate = 0; -#define NOISE_MIN_SAMPLE -#ifdef NOISE_MIN_SAMPLE - const float NOISE_GATE_HEIGHT = 12.f; + const float NOISE_GATE_HEIGHT = 7.f; const int NOISE_GATE_WIDTH = 5; 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 - + const int NOISE_GATE_FRAMES_TO_AVERAGE = 5; for (int i = 0; i < NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL; i++) { thisSample = fabsf(monoAudioSamples[i]); loudness += thisSample; // Noise Reduction: Count peaks above the average loudness - if (thisSample > (_averageInputLoudness * NOISE_GATE_HEIGHT)) { + if (thisSample > (_noiseGateMeasuredFloor * NOISE_GATE_HEIGHT)) { samplesOverNoiseGate++; } } _lastInputLoudness = loudness / NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL; - //qDebug("%.1f", _lastInputLoudness); -#ifdef NOISE_MIN_SAMPLE + float averageOfAllSampleFrames = 0.f; _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]; + for (int i = 0; i <= NUMBER_OF_NOISE_SAMPLE_FRAMES - NOISE_GATE_FRAMES_TO_AVERAGE; i+= NOISE_GATE_FRAMES_TO_AVERAGE) { + float thisAverage = 0.0f; + for (int j = i; j < i + NOISE_GATE_FRAMES_TO_AVERAGE; j++) { + thisAverage += _noiseSampleFrames[j]; + averageOfAllSampleFrames += _noiseSampleFrames[j]; + } + thisAverage /= NOISE_GATE_FRAMES_TO_AVERAGE; + + if (thisAverage < smallestSample) { + smallestSample = thisAverage; } } - _averageInputLoudness = smallestSample; + averageOfAllSampleFrames /= NUMBER_OF_NOISE_SAMPLE_FRAMES; + _noiseGateMeasuredFloor = smallestSample; _noiseGateSampleCounter = 0; - //qDebug("smallest sample = %.1f", _averageInputLoudness); + qDebug("smallest sample = %.1f, avg of all = %.1f", _noiseGateMeasuredFloor, averageOfAllSampleFrames); } -#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) { _noiseGateOpen = true; diff --git a/interface/src/Audio.h b/interface/src/Audio.h index 5028024a0c..34a3daad30 100644 --- a/interface/src/Audio.h +++ b/interface/src/Audio.h @@ -45,7 +45,7 @@ public: void render(int screenWidth, int screenHeight); - float getLastInputLoudness() const { return glm::max(_lastInputLoudness - _averageInputLoudness, 0.f); } + float getLastInputLoudness() const { return glm::max(_lastInputLoudness - _noiseGateMeasuredFloor, 0.f); } void setNoiseGateEnabled(bool noiseGateEnabled) { _noiseGateEnabled = noiseGateEnabled; } @@ -109,7 +109,7 @@ private: float _measuredJitter; int16_t _jitterBufferSamples; float _lastInputLoudness; - float _averageInputLoudness; + float _noiseGateMeasuredFloor; float* _noiseSampleFrames; int _noiseGateSampleCounter; bool _noiseGateOpen; From 595eb38c72b12ba4c825274eceece2d37a45d24a Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Wed, 12 Feb 2014 22:57:13 -0800 Subject: [PATCH 7/8] comment out debug --- interface/src/Audio.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 30352639c0..75d2a5751c 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -413,7 +413,7 @@ void Audio::handleAudioInput() { averageOfAllSampleFrames /= NUMBER_OF_NOISE_SAMPLE_FRAMES; _noiseGateMeasuredFloor = smallestSample; _noiseGateSampleCounter = 0; - qDebug("smallest sample = %.1f, avg of all = %.1f", _noiseGateMeasuredFloor, averageOfAllSampleFrames); + //qDebug("smallest sample = %.1f, avg of all = %.1f", _noiseGateMeasuredFloor, averageOfAllSampleFrames); } if (_noiseGateEnabled) { From 50df17dc10060c571697926053669b3b18881965 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Wed, 12 Feb 2014 23:37:19 -0800 Subject: [PATCH 8/8] fix windows build buster --- interface/src/Audio.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 75d2a5751c..0cf67be2bf 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -397,7 +397,7 @@ void Audio::handleAudioInput() { float averageOfAllSampleFrames = 0.f; _noiseSampleFrames[_noiseGateSampleCounter++] = _lastInputLoudness; if (_noiseGateSampleCounter == NUMBER_OF_NOISE_SAMPLE_FRAMES) { - float smallestSample = MAXFLOAT; + float smallestSample = FLT_MAX; for (int i = 0; i <= NUMBER_OF_NOISE_SAMPLE_FRAMES - NOISE_GATE_FRAMES_TO_AVERAGE; i+= NOISE_GATE_FRAMES_TO_AVERAGE) { float thisAverage = 0.0f; for (int j = i; j < i + NOISE_GATE_FRAMES_TO_AVERAGE; j++) {