From 8b9e0426b24e6ec01ca53b9ec75683aadbb8fbcc Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Fri, 12 Jul 2013 21:34:48 -0700 Subject: [PATCH 1/6] Simple glassy collision sound --- interface/src/Application.h | 1 + interface/src/Audio.cpp | 25 ++++++++++++++++++++++--- interface/src/Audio.h | 6 +++++- interface/src/Avatar.cpp | 8 ++++++++ 4 files changed, 36 insertions(+), 4 deletions(-) diff --git a/interface/src/Application.h b/interface/src/Application.h index c6bbd4eec2..9e8e359479 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -84,6 +84,7 @@ public: const glm::vec3 getMouseVoxelWorldCoordinates(const VoxelDetail _mouseVoxel); Avatar* getAvatar() { return &_myAvatar; } + Audio* getAudio() { return &_audio; } Camera* getCamera() { return &_myCamera; } ViewFrustum* getViewFrustum() { return &_viewFrustum; } VoxelSystem* getVoxels() { return &_voxels; } diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 7af42478d5..540e7b1e1e 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -326,7 +326,9 @@ Audio::Audio(Oscilloscope* scope, int16_t initialJitterBufferSamples) : _lastYawMeasuredMaximum(0), _flangeIntensity(0.0f), _flangeRate(0.0f), - _flangeWeight(0.0f) + _flangeWeight(0.0f), + _collisionSoundMagnitude(0.0f), + _proceduralEffectSample(0) { outputPortAudioError(Pa_Initialize()); @@ -591,12 +593,29 @@ void Audio::addProceduralSounds(int16_t* inputBuffer, int numSamples) { float speed = glm::length(_lastVelocity); float volume = VOLUME_BASELINE * (1.f - speed / MAX_AUDIBLE_VELOCITY); + // Test tone (should be continuous!) + /* + for (int i = 0; i < numSamples; i++) { + inputBuffer[i] += (int16_t) (_proceduralEffectSample + i)%16 * 10; + }*/ + // Add a noise-modulated sinewave with volume that tapers off with speed increasing - if ((speed > MIN_AUDIBLE_VELOCITY) && (speed < MAX_AUDIBLE_VELOCITY)) { + if (0) { //((speed > MIN_AUDIBLE_VELOCITY) && (speed < MAX_AUDIBLE_VELOCITY)) { for (int i = 0; i < numSamples; i++) { - inputBuffer[i] += (int16_t)((sinf((float) i / SOUND_PITCH * speed) * randFloat()) * volume * speed); + inputBuffer[i] += (int16_t)((sinf((float) (_proceduralEffectSample + i) / SOUND_PITCH * speed) * (1.f + randFloat() * 0.0f)) * volume * speed); } } + const float COLLISION_SOUND_CUTOFF_LEVEL = 5.0f; + const float COLLISION_SOUND_PITCH_1 = 2.0f; + const float COLLISION_SOUND_DECAY = 1.f/1024.f; + const float COLLISION_VOLUME_BASELINE = 10.f; + if (_collisionSoundMagnitude > COLLISION_SOUND_CUTOFF_LEVEL) { + for (int i = 0; i < numSamples; i++) { + inputBuffer[i] += (int16_t) ((sinf((float) (_proceduralEffectSample + i) / COLLISION_SOUND_PITCH_1) * COLLISION_VOLUME_BASELINE * _collisionSoundMagnitude)); + _collisionSoundMagnitude *= (1.f - COLLISION_SOUND_DECAY); + } + } + _proceduralEffectSample += numSamples; } // ----------------------------------------------------------- diff --git a/interface/src/Audio.h b/interface/src/Audio.h index a3c8cf1046..78b298644b 100644 --- a/interface/src/Audio.h +++ b/interface/src/Audio.h @@ -44,6 +44,8 @@ public: void lowPassFilter(int16_t* inputBuffer); + void setCollisionSoundMagnitude(float collisionSoundMagnitude) { _collisionSoundMagnitude = collisionSoundMagnitude; } + void ping(); // Call periodically to eventually perform round trip time analysis, @@ -81,7 +83,9 @@ private: float _flangeIntensity; float _flangeRate; float _flangeWeight; - + float _collisionSoundMagnitude; + int _proceduralEffectSample; + // Audio callback in class context. inline void performIO(int16_t* inputLeft, int16_t* outputLeft, int16_t* outputRight); diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp index 881b436bf2..7d306b307a 100755 --- a/interface/src/Avatar.cpp +++ b/interface/src/Avatar.cpp @@ -873,6 +873,7 @@ void Avatar::updateCollisionWithEnvironment() { _position - up * (_pelvisFloatingHeight - radius), _position + up * (_height - _pelvisFloatingHeight - radius), radius, penetration)) { applyHardCollision(penetration, ENVIRONMENT_SURFACE_ELASTICITY, ENVIRONMENT_SURFACE_DAMPING); + } } @@ -910,6 +911,13 @@ void Avatar::applyHardCollision(const glm::vec3& penetration, float elasticity, // If moving really slowly after a collision, and not applying forces, stop altogether _velocity *= 0.f; } + // Push the collision into the audio system for procedural effects + const float AUDIBLE_COLLISION_THRESHOLD = 200.f; + const float COLLISION_VOLUME = 10000.f; + float collisionSoundLevel = penetrationLength * COLLISION_VOLUME; + if (collisionSoundLevel > AUDIBLE_COLLISION_THRESHOLD) { + Application::getInstance()->getAudio()->setCollisionSoundMagnitude(collisionSoundLevel); + } } } From f8f6b295597bc0a747b6c0cc62d22932ed3e0d7b Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Mon, 15 Jul 2013 14:24:21 -0700 Subject: [PATCH 2/6] Audio collision sounds are played locally as well as injected --- interface/src/Audio.cpp | 39 ++++++++++++++++++++++++--------------- interface/src/Audio.h | 2 +- interface/src/Head.cpp | 6 ++++-- 3 files changed, 29 insertions(+), 18 deletions(-) diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 540e7b1e1e..a724f7b288 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -75,9 +75,12 @@ inline void Audio::performIO(int16_t* inputLeft, int16_t* outputLeft, int16_t* o NodeList* nodeList = NodeList::getInstance(); Application* interface = Application::getInstance(); Avatar* interfaceAvatar = interface->getAvatar(); - + + memset(outputLeft, 0, PACKET_LENGTH_BYTES_PER_CHANNEL); + memset(outputRight, 0, PACKET_LENGTH_BYTES_PER_CHANNEL); + // Add Procedural effects to input samples - addProceduralSounds(inputLeft, BUFFER_LENGTH_SAMPLES_PER_CHANNEL); + addProceduralSounds(inputLeft, outputLeft, outputRight, BUFFER_LENGTH_SAMPLES_PER_CHANNEL); if (nodeList && inputLeft) { @@ -129,12 +132,8 @@ inline void Audio::performIO(int16_t* inputLeft, int16_t* outputLeft, int16_t* o interface->getBandwidthMeter()->outputStream(BandwidthMeter::AUDIO) .updateValue(BUFFER_LENGTH_BYTES_PER_CHANNEL + leadingBytes); } - } - - memset(outputLeft, 0, PACKET_LENGTH_BYTES_PER_CHANNEL); - memset(outputRight, 0, PACKET_LENGTH_BYTES_PER_CHANNEL); - + AudioRingBuffer* ringBuffer = &_ringBuffer; // if there is anything in the ring buffer, decide what to do: @@ -245,11 +244,11 @@ inline void Audio::performIO(int16_t* inputLeft, int16_t* outputLeft, int16_t* o } } #ifndef TEST_AUDIO_LOOPBACK - outputLeft[s] = leftSample; - outputRight[s] = rightSample; + outputLeft[s] += leftSample; + outputRight[s] += rightSample; #else - outputLeft[s] = inputLeft[s]; - outputRight[s] = inputLeft[s]; + outputLeft[s] += inputLeft[s]; + outputRight[s] += inputLeft[s]; #endif } ringBuffer->setNextOutput(ringBuffer->getNextOutput() + PACKET_LENGTH_SAMPLES); @@ -584,7 +583,10 @@ void Audio::lowPassFilter(int16_t* inputBuffer) { } // Take a pointer to the acquired microphone input samples and add procedural sounds -void Audio::addProceduralSounds(int16_t* inputBuffer, int numSamples) { +void Audio::addProceduralSounds(int16_t* inputBuffer, + int16_t* outputLeft, + int16_t* outputRight, + int numSamples) { const float MAX_AUDIBLE_VELOCITY = 6.0; const float MIN_AUDIBLE_VELOCITY = 0.1; const int VOLUME_BASELINE = 400; @@ -600,18 +602,25 @@ void Audio::addProceduralSounds(int16_t* inputBuffer, int numSamples) { }*/ // Add a noise-modulated sinewave with volume that tapers off with speed increasing - if (0) { //((speed > MIN_AUDIBLE_VELOCITY) && (speed < MAX_AUDIBLE_VELOCITY)) { + if ((speed > MIN_AUDIBLE_VELOCITY) && (speed < MAX_AUDIBLE_VELOCITY)) { for (int i = 0; i < numSamples; i++) { - inputBuffer[i] += (int16_t)((sinf((float) (_proceduralEffectSample + i) / SOUND_PITCH * speed) * (1.f + randFloat() * 0.0f)) * volume * speed); + //inputBuffer[i] += (int16_t)((sinf((float) (_proceduralEffectSample + i) / SOUND_PITCH * speed) * (1.f + randFloat() * 0.0f)) * volume * speed); + inputBuffer[i] += (int16_t)(sinf((float) (_proceduralEffectSample + i) / SOUND_PITCH ) * volume * (1.f + randFloat() * 0.25f) * speed); + + } } const float COLLISION_SOUND_CUTOFF_LEVEL = 5.0f; const float COLLISION_SOUND_PITCH_1 = 2.0f; const float COLLISION_SOUND_DECAY = 1.f/1024.f; const float COLLISION_VOLUME_BASELINE = 10.f; + int sample; if (_collisionSoundMagnitude > COLLISION_SOUND_CUTOFF_LEVEL) { for (int i = 0; i < numSamples; i++) { - inputBuffer[i] += (int16_t) ((sinf((float) (_proceduralEffectSample + i) / COLLISION_SOUND_PITCH_1) * COLLISION_VOLUME_BASELINE * _collisionSoundMagnitude)); + sample = (int16_t) ((sinf((float) (_proceduralEffectSample + i) / COLLISION_SOUND_PITCH_1) * COLLISION_VOLUME_BASELINE * _collisionSoundMagnitude)); + inputBuffer[i] += sample; + outputLeft[i] += sample; + outputRight[i] += sample; _collisionSoundMagnitude *= (1.f - COLLISION_SOUND_DECAY); } } diff --git a/interface/src/Audio.h b/interface/src/Audio.h index 78b298644b..715cfeafc8 100644 --- a/interface/src/Audio.h +++ b/interface/src/Audio.h @@ -97,7 +97,7 @@ private: inline void analyzePing(); // Add sounds that we want the user to not hear themselves, by adding on top of mic input signal - void addProceduralSounds(int16_t* inputBuffer, int numSamples); + void addProceduralSounds(int16_t* inputBuffer, int16_t* outputLeft, int16_t* outputRight, int numSamples); // Audio callback called by portaudio. Calls 'performIO'. diff --git a/interface/src/Head.cpp b/interface/src/Head.cpp index 44d62e695d..18141bc2b4 100644 --- a/interface/src/Head.cpp +++ b/interface/src/Head.cpp @@ -227,7 +227,8 @@ void Head::simulate(float deltaTime, bool isMine) { const float CAMERA_FOLLOW_HEAD_RATE_MAX = 0.5f; const float CAMERA_FOLLOW_HEAD_RATE_RAMP_RATE = 1.05f; const float CAMERA_STOP_TOLERANCE_DEGREES = 0.1f; - const float CAMERA_START_TOLERANCE_DEGREES = 2.0f; + const float CAMERA_PITCH_START_TOLERANCE_DEGREES = 10.0f; + const float CAMERA_YAW_START_TOLERANCE_DEGREES = 3.0f; float cameraHeadAngleDifference = glm::length(glm::vec2(_pitch - _cameraPitch, _yaw - _cameraYaw)); if (_isCameraMoving) { _cameraFollowHeadRate = glm::clamp(_cameraFollowHeadRate * CAMERA_FOLLOW_HEAD_RATE_RAMP_RATE, @@ -240,7 +241,8 @@ void Head::simulate(float deltaTime, bool isMine) { _isCameraMoving = false; } } else { - if (cameraHeadAngleDifference > CAMERA_START_TOLERANCE_DEGREES) { + if ((fabs(_pitch - _cameraPitch) > CAMERA_PITCH_START_TOLERANCE_DEGREES) || + (fabs(_yaw - _cameraYaw) > CAMERA_YAW_START_TOLERANCE_DEGREES)) { _isCameraMoving = true; _cameraFollowHeadRate = CAMERA_FOLLOW_HEAD_RATE_START; } From 26c0eb2dea0556bf0bd011d08a0c576d429b3c3e Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Mon, 15 Jul 2013 16:27:46 -0700 Subject: [PATCH 3/6] Start to add heartbeat --- interface/src/Audio.cpp | 10 +++++++++- interface/src/Audio.h | 1 + 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index a724f7b288..a2b3f08535 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -327,7 +327,8 @@ Audio::Audio(Oscilloscope* scope, int16_t initialJitterBufferSamples) : _flangeRate(0.0f), _flangeWeight(0.0f), _collisionSoundMagnitude(0.0f), - _proceduralEffectSample(0) + _proceduralEffectSample(0), + _heartbeatMagnitude(0.0f) { outputPortAudioError(Pa_Initialize()); @@ -601,6 +602,9 @@ void Audio::addProceduralSounds(int16_t* inputBuffer, inputBuffer[i] += (int16_t) (_proceduralEffectSample + i)%16 * 10; }*/ + // + // Travelling noise + // // Add a noise-modulated sinewave with volume that tapers off with speed increasing if ((speed > MIN_AUDIBLE_VELOCITY) && (speed < MAX_AUDIBLE_VELOCITY)) { for (int i = 0; i < numSamples; i++) { @@ -624,6 +628,10 @@ void Audio::addProceduralSounds(int16_t* inputBuffer, _collisionSoundMagnitude *= (1.f - COLLISION_SOUND_DECAY); } } + + //if (_heartbeatMagnitude > 0.0f) { + // + //} _proceduralEffectSample += numSamples; } diff --git a/interface/src/Audio.h b/interface/src/Audio.h index 715cfeafc8..1ab671a30b 100644 --- a/interface/src/Audio.h +++ b/interface/src/Audio.h @@ -85,6 +85,7 @@ private: float _flangeWeight; float _collisionSoundMagnitude; int _proceduralEffectSample; + float _heartbeatMagnitude; // Audio callback in class context. inline void performIO(int16_t* inputLeft, int16_t* outputLeft, int16_t* outputRight); From edf031b98566e73efe3dee0499e26bce90193c81 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Mon, 15 Jul 2013 22:42:55 -0700 Subject: [PATCH 4/6] improve collision sounds, difference between ground and voxels --- interface/src/Audio.cpp | 18 +++++++++++++----- interface/src/Audio.h | 5 +++++ interface/src/Avatar.cpp | 34 +++++++++++++++++++++++++++------- interface/src/Avatar.h | 1 + 4 files changed, 46 insertions(+), 12 deletions(-) diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 1e04e563a2..8b2856a7c9 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -333,6 +333,9 @@ Audio::Audio(Oscilloscope* scope, int16_t initialJitterBufferSamples) : _flangeRate(0.0f), _flangeWeight(0.0f), _collisionSoundMagnitude(0.0f), + _collisionSoundFrequency(0.0f), + _collisionSoundNoise(0.0f), + _collisionSoundDuration(0.0f), _proceduralEffectSample(0), _heartbeatMagnitude(0.0f) { @@ -621,17 +624,16 @@ void Audio::addProceduralSounds(int16_t* inputBuffer, } } const float COLLISION_SOUND_CUTOFF_LEVEL = 5.0f; - const float COLLISION_SOUND_PITCH_1 = 2.0f; - const float COLLISION_SOUND_DECAY = 1.f/1024.f; - const float COLLISION_VOLUME_BASELINE = 10.f; int sample; if (_collisionSoundMagnitude > COLLISION_SOUND_CUTOFF_LEVEL) { for (int i = 0; i < numSamples; i++) { - sample = (int16_t) ((sinf((float) (_proceduralEffectSample + i) / COLLISION_SOUND_PITCH_1) * COLLISION_VOLUME_BASELINE * _collisionSoundMagnitude)); + sample = (int16_t) (((sinf(((float)_proceduralEffectSample + (float)i) * _collisionSoundFrequency) * (1.f - _collisionSoundNoise) + + ((randFloat() * 2.f - 1.0f) * _collisionSoundNoise)) + * _collisionSoundMagnitude)); inputBuffer[i] += sample; outputLeft[i] += sample; outputRight[i] += sample; - _collisionSoundMagnitude *= (1.f - COLLISION_SOUND_DECAY); + _collisionSoundMagnitude *= _collisionSoundDuration; } } @@ -641,6 +643,12 @@ void Audio::addProceduralSounds(int16_t* inputBuffer, _proceduralEffectSample += numSamples; } +void Audio::startCollisionSound(float magnitude, float frequency, float noise, float duration) { + _collisionSoundMagnitude = magnitude; + _collisionSoundFrequency = frequency; + _collisionSoundNoise = noise; + _collisionSoundDuration = duration; +} // ----------------------------------------------------------- // Accoustic ping (audio system round trip time determination) // ----------------------------------------------------------- diff --git a/interface/src/Audio.h b/interface/src/Audio.h index 1ab671a30b..a43e05e3ec 100644 --- a/interface/src/Audio.h +++ b/interface/src/Audio.h @@ -46,6 +46,8 @@ public: void setCollisionSoundMagnitude(float collisionSoundMagnitude) { _collisionSoundMagnitude = collisionSoundMagnitude; } + void startCollisionSound(float magnitude, float frequency, float noise, float duration); + void ping(); // Call periodically to eventually perform round trip time analysis, @@ -84,6 +86,9 @@ private: float _flangeRate; float _flangeWeight; float _collisionSoundMagnitude; + float _collisionSoundFrequency; + float _collisionSoundNoise; + float _collisionSoundDuration; int _proceduralEffectSample; float _heartbeatMagnitude; diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp index 289d5548c4..b3868f6ea7 100755 --- a/interface/src/Avatar.cpp +++ b/interface/src/Avatar.cpp @@ -873,12 +873,15 @@ void Avatar::updateCollisionWithEnvironment() { float radius = _height * 0.125f; const float ENVIRONMENT_SURFACE_ELASTICITY = 1.0f; const float ENVIRONMENT_SURFACE_DAMPING = 0.01; + const float ENVIRONMENT_COLLISION_FREQUENCY = 0.05f; glm::vec3 penetration; if (Application::getInstance()->getEnvironment()->findCapsulePenetration( _position - up * (_pelvisFloatingHeight - radius), _position + up * (_height - _pelvisFloatingHeight - radius), radius, penetration)) { + createCollisionSound(penetration, ENVIRONMENT_COLLISION_FREQUENCY); applyHardCollision(penetration, ENVIRONMENT_SURFACE_ELASTICITY, ENVIRONMENT_SURFACE_DAMPING); + } } @@ -887,10 +890,12 @@ void Avatar::updateCollisionWithVoxels() { float radius = _height * 0.125f; const float VOXEL_ELASTICITY = 1.4f; const float VOXEL_DAMPING = 0.0; + const float VOXEL_COLLISION_FREQUENCY = 0.5f; glm::vec3 penetration; if (Application::getInstance()->getVoxels()->findCapsulePenetration( _position - glm::vec3(0.0f, _pelvisFloatingHeight - radius, 0.0f), _position + glm::vec3(0.0f, _height - _pelvisFloatingHeight - radius, 0.0f), radius, penetration)) { + createCollisionSound(penetration, VOXEL_COLLISION_FREQUENCY); applyHardCollision(penetration, VOXEL_ELASTICITY, VOXEL_DAMPING); } } @@ -916,16 +921,31 @@ void Avatar::applyHardCollision(const glm::vec3& penetration, float elasticity, // If moving really slowly after a collision, and not applying forces, stop altogether _velocity *= 0.f; } - // Push the collision into the audio system for procedural effects - const float AUDIBLE_COLLISION_THRESHOLD = 200.f; - const float COLLISION_VOLUME = 10000.f; - float collisionSoundLevel = penetrationLength * COLLISION_VOLUME; - if (collisionSoundLevel > AUDIBLE_COLLISION_THRESHOLD) { - Application::getInstance()->getAudio()->setCollisionSoundMagnitude(collisionSoundLevel); - } } } +void Avatar::createCollisionSound(const glm::vec3 &penetration, float frequency) { + // Push the collision into the audio system for procedural effects + const float AUDIBLE_COLLISION_THRESHOLD = 0.2f; + const float COLLISION_VOLUME = 1000.f; + const float MAX_COLLISION_VOLUME = 15000.f; + const float DURATION_SCALING = 0.004f; + float velocityTowardCollision = glm::dot(_velocity, glm::normalize(penetration)); + float velocityTangentToCollision = glm::length(_velocity) - velocityTowardCollision; + if (velocityTowardCollision > AUDIBLE_COLLISION_THRESHOLD) { + Application::getInstance()->getAudio()->startCollisionSound( + fmax(COLLISION_VOLUME * velocityTowardCollision, MAX_COLLISION_VOLUME), + frequency, + fmin(velocityTangentToCollision / velocityTowardCollision, 1.f), + 1.f - DURATION_SCALING * powf(frequency, 0.5f) / velocityTowardCollision); + + } + //float collisionSoundLevel = penetrationLength * COLLISION_VOLUME; + //if (collisionSoundLevel > AUDIBLE_COLLISION_THRESHOLD) { + // Application::getInstance()->getAudio()->setCollisionSoundMagnitude(collisionSoundLevel); + //} +} + void Avatar::updateAvatarCollisions(float deltaTime) { // Reset detector for nearest avatar diff --git a/interface/src/Avatar.h b/interface/src/Avatar.h index 643a187a67..31c9b573b8 100755 --- a/interface/src/Avatar.h +++ b/interface/src/Avatar.h @@ -262,6 +262,7 @@ private: void updateCollisionWithEnvironment(); void updateCollisionWithVoxels(); void applyHardCollision(const glm::vec3& penetration, float elasticity, float damping); + void createCollisionSound(const glm::vec3& penetration, float frequency); void applyCollisionWithOtherAvatar( Avatar * other, float deltaTime ); void checkForMouseRayTouching(); }; From 192ae637893c3b22a16cbf3a3504595490cae64d Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Tue, 16 Jul 2013 16:40:50 -0700 Subject: [PATCH 5/6] Colliding with ground, voxels makes interesting sounds and flashes your display --- interface/src/Application.cpp | 6 +++- interface/src/Application.h | 7 +++- interface/src/Audio.cpp | 30 ++++++++--------- interface/src/Audio.h | 4 +-- interface/src/Avatar.cpp | 61 +++++++++++++++++++++-------------- interface/src/Avatar.h | 8 +++-- interface/src/Util.cpp | 34 +++++++++++++------ interface/src/Util.h | 5 ++- 8 files changed, 97 insertions(+), 58 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 644d5524f0..a2fe2072c6 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -188,6 +188,7 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : _isTouchPressed(false), _yawFromTouch(0.0f), _pitchFromTouch(0.0f), + _groundPlaneImpact(0.0f), _mousePressed(false), _mouseVoxelScale(1.0f / 1024.0f), _justEditedVoxel(false), @@ -2516,7 +2517,7 @@ void Application::displaySide(Camera& whichCamera) { //draw a grid ground plane.... if (_renderGroundPlaneOn->isChecked()) { - drawGroundPlaneGrid(EDGE_SIZE_GROUND_PLANE); + renderGroundPlaneGrid(EDGE_SIZE_GROUND_PLANE, _audio.getCollisionSoundMagnitude()); } // Draw voxels if (_renderVoxels->isChecked()) { @@ -2592,6 +2593,9 @@ void Application::displayOverlay() { glDisable(GL_DEPTH_TEST); glDisable(GL_LIGHTING); + // Display a single screen-size quad to + renderCollisionOverlay(_glWidget->width(), _glWidget->height(), _audio.getCollisionSoundMagnitude()); + #ifndef _WIN32 _audio.render(_glWidget->width(), _glWidget->height()); if (_oscilloscopeOn->isChecked()) { diff --git a/interface/src/Application.h b/interface/src/Application.h index b46ee20111..cb1896c4de 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -101,6 +101,9 @@ public: QNetworkAccessManager* getNetworkAccessManager() { return _networkAccessManager; } GeometryCache* getGeometryCache() { return &_geometryCache; } + void setGroundPlaneImpact(float groundPlaneImpact) { _groundPlaneImpact = groundPlaneImpact; } + + private slots: void timer(); @@ -206,7 +209,7 @@ private: void deleteVoxelUnderCursor(); void eyedropperVoxelUnderCursor(); void resetSensors(); - + void setMenuShortcutsEnabled(bool enabled); void updateCursor(); @@ -344,6 +347,8 @@ private: float _yawFromTouch; float _pitchFromTouch; + float _groundPlaneImpact; + VoxelDetail _mouseVoxelDragging; glm::vec3 _voxelThrust; bool _mousePressed; // true if mouse has been pressed (clear when finished) diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 8b2856a7c9..dc36968c3b 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -605,11 +605,7 @@ void Audio::addProceduralSounds(int16_t* inputBuffer, float speed = glm::length(_lastVelocity); float volume = VOLUME_BASELINE * (1.f - speed / MAX_AUDIBLE_VELOCITY); - // Test tone (should be continuous!) - /* - for (int i = 0; i < numSamples; i++) { - inputBuffer[i] += (int16_t) (_proceduralEffectSample + i)%16 * 10; - }*/ + int sample; // // Travelling noise @@ -617,32 +613,32 @@ void Audio::addProceduralSounds(int16_t* inputBuffer, // Add a noise-modulated sinewave with volume that tapers off with speed increasing if ((speed > MIN_AUDIBLE_VELOCITY) && (speed < MAX_AUDIBLE_VELOCITY)) { for (int i = 0; i < numSamples; i++) { - //inputBuffer[i] += (int16_t)((sinf((float) (_proceduralEffectSample + i) / SOUND_PITCH * speed) * (1.f + randFloat() * 0.0f)) * volume * speed); inputBuffer[i] += (int16_t)(sinf((float) (_proceduralEffectSample + i) / SOUND_PITCH ) * volume * (1.f + randFloat() * 0.25f) * speed); - - } } - const float COLLISION_SOUND_CUTOFF_LEVEL = 5.0f; - int sample; + const float COLLISION_SOUND_CUTOFF_LEVEL = 0.01f; + const float COLLISION_SOUND_MAX_VOLUME = 1000.f; + const float UP_MAJOR_FIFTH = powf(1.5f, 4.0f); + float t; if (_collisionSoundMagnitude > COLLISION_SOUND_CUTOFF_LEVEL) { for (int i = 0; i < numSamples; i++) { - sample = (int16_t) (((sinf(((float)_proceduralEffectSample + (float)i) * _collisionSoundFrequency) * (1.f - _collisionSoundNoise) - + ((randFloat() * 2.f - 1.0f) * _collisionSoundNoise)) - * _collisionSoundMagnitude)); + t = (float) _proceduralEffectSample + (float) i; + sample = sinf(t * _collisionSoundFrequency) + + sinf(t * _collisionSoundFrequency / 4.f) + + sinf(t * _collisionSoundFrequency / 16.f * UP_MAJOR_FIFTH); + sample *= _collisionSoundMagnitude * COLLISION_SOUND_MAX_VOLUME; inputBuffer[i] += sample; outputLeft[i] += sample; outputRight[i] += sample; _collisionSoundMagnitude *= _collisionSoundDuration; } } - - //if (_heartbeatMagnitude > 0.0f) { - // - //} _proceduralEffectSample += numSamples; } +// +// Starts a collision sound. magnitude is 0-1, with 1 the loudest possible sound. +// void Audio::startCollisionSound(float magnitude, float frequency, float noise, float duration) { _collisionSoundMagnitude = magnitude; _collisionSoundFrequency = frequency; diff --git a/interface/src/Audio.h b/interface/src/Audio.h index a43e05e3ec..5954361444 100644 --- a/interface/src/Audio.h +++ b/interface/src/Audio.h @@ -43,10 +43,10 @@ public: int getJitterBufferSamples() { return _jitterBufferSamples; }; void lowPassFilter(int16_t* inputBuffer); - - void setCollisionSoundMagnitude(float collisionSoundMagnitude) { _collisionSoundMagnitude = collisionSoundMagnitude; } void startCollisionSound(float magnitude, float frequency, float noise, float duration); + float getCollisionSoundMagnitude() { return _collisionSoundMagnitude; }; + void ping(); diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp index b3868f6ea7..e34a4ff194 100755 --- a/interface/src/Avatar.cpp +++ b/interface/src/Avatar.cpp @@ -545,8 +545,8 @@ void Avatar::simulate(float deltaTime, Transmitter* transmitter) { _position += _scale * _gravity * (GRAVITY_EARTH * deltaTime) * deltaTime; } - updateCollisionWithEnvironment(); - updateCollisionWithVoxels(); + updateCollisionWithEnvironment(deltaTime); + updateCollisionWithVoxels(deltaTime); updateAvatarCollisions(deltaTime); } @@ -867,7 +867,7 @@ void Avatar::updateCollisionWithSphere(glm::vec3 position, float radius, float d } } -void Avatar::updateCollisionWithEnvironment() { +void Avatar::updateCollisionWithEnvironment(float deltaTime) { glm::vec3 up = getBodyUpDirection(); float radius = _height * 0.125f; @@ -878,7 +878,12 @@ void Avatar::updateCollisionWithEnvironment() { if (Application::getInstance()->getEnvironment()->findCapsulePenetration( _position - up * (_pelvisFloatingHeight - radius), _position + up * (_height - _pelvisFloatingHeight - radius), radius, penetration)) { - createCollisionSound(penetration, ENVIRONMENT_COLLISION_FREQUENCY); + float velocityTowardCollision = glm::dot(_velocity, glm::normalize(penetration)); + if (velocityTowardCollision > 0.2) { + Application::getInstance()->setGroundPlaneImpact(1.0f); + } + updateCollisionSound(penetration, deltaTime, ENVIRONMENT_COLLISION_FREQUENCY); + applyHardCollision(penetration, ENVIRONMENT_SURFACE_ELASTICITY, ENVIRONMENT_SURFACE_DAMPING); @@ -886,7 +891,7 @@ void Avatar::updateCollisionWithEnvironment() { } -void Avatar::updateCollisionWithVoxels() { +void Avatar::updateCollisionWithVoxels(float deltaTime) { float radius = _height * 0.125f; const float VOXEL_ELASTICITY = 1.4f; const float VOXEL_DAMPING = 0.0; @@ -895,7 +900,7 @@ void Avatar::updateCollisionWithVoxels() { if (Application::getInstance()->getVoxels()->findCapsulePenetration( _position - glm::vec3(0.0f, _pelvisFloatingHeight - radius, 0.0f), _position + glm::vec3(0.0f, _height - _pelvisFloatingHeight - radius, 0.0f), radius, penetration)) { - createCollisionSound(penetration, VOXEL_COLLISION_FREQUENCY); + updateCollisionSound(penetration, deltaTime, VOXEL_COLLISION_FREQUENCY); applyHardCollision(penetration, VOXEL_ELASTICITY, VOXEL_DAMPING); } } @@ -924,26 +929,34 @@ void Avatar::applyHardCollision(const glm::vec3& penetration, float elasticity, } } -void Avatar::createCollisionSound(const glm::vec3 &penetration, float frequency) { - // Push the collision into the audio system for procedural effects - const float AUDIBLE_COLLISION_THRESHOLD = 0.2f; - const float COLLISION_VOLUME = 1000.f; - const float MAX_COLLISION_VOLUME = 15000.f; +void Avatar::updateCollisionSound(const glm::vec3 &penetration, float deltaTime, float frequency) { + // consider whether to have the collision make a sound + const float AUDIBLE_COLLISION_THRESHOLD = 0.02f; + const float COLLISION_LOUDNESS = 1.f; const float DURATION_SCALING = 0.004f; - float velocityTowardCollision = glm::dot(_velocity, glm::normalize(penetration)); - float velocityTangentToCollision = glm::length(_velocity) - velocityTowardCollision; - if (velocityTowardCollision > AUDIBLE_COLLISION_THRESHOLD) { - Application::getInstance()->getAudio()->startCollisionSound( - fmax(COLLISION_VOLUME * velocityTowardCollision, MAX_COLLISION_VOLUME), - frequency, - fmin(velocityTangentToCollision / velocityTowardCollision, 1.f), - 1.f - DURATION_SCALING * powf(frequency, 0.5f) / velocityTowardCollision); - + const float NOISE_SCALING = 0.1f; + glm::vec3 velocity = _velocity; + glm::vec3 gravity = getGravity(); + + if (glm::length(gravity) > EPSILON) { + // If gravity is on, remove the effect of gravity on velocity for this + // frame, so that we are not constantly colliding with the surface + velocity -= _scale * glm::length(gravity) * GRAVITY_EARTH * deltaTime * glm::normalize(gravity); + } + float velocityTowardCollision = glm::dot(velocity, glm::normalize(penetration)); + float velocityTangentToCollision = glm::length(velocity) - velocityTowardCollision; + + if (velocityTowardCollision > AUDIBLE_COLLISION_THRESHOLD) { + // Volume is proportional to collision velocity + // Base frequency is modified upward by the angle of the collision + // Noise is a function of the angle of collision + // Duration of the sound is a function of both base frequency and velocity of impact + Application::getInstance()->getAudio()->startCollisionSound( + fmin(COLLISION_LOUDNESS * velocityTowardCollision, 1.f), + frequency * (1.f + velocityTangentToCollision / velocityTowardCollision), + fmin(velocityTangentToCollision / velocityTowardCollision * NOISE_SCALING, 1.f), + 1.f - DURATION_SCALING * powf(frequency, 0.5f) / velocityTowardCollision); } - //float collisionSoundLevel = penetrationLength * COLLISION_VOLUME; - //if (collisionSoundLevel > AUDIBLE_COLLISION_THRESHOLD) { - // Application::getInstance()->getAudio()->setCollisionSoundMagnitude(collisionSoundLevel); - //} } void Avatar::updateAvatarCollisions(float deltaTime) { diff --git a/interface/src/Avatar.h b/interface/src/Avatar.h index 31c9b573b8..fa605fa425 100755 --- a/interface/src/Avatar.h +++ b/interface/src/Avatar.h @@ -159,6 +159,8 @@ public: glm::quat getOrientation () const; glm::quat getWorldAlignedOrientation() const; + glm::vec3 getGravity () const { return _gravity; } + glm::vec3 getUprightHeadPosition() const; AvatarVoxelSystem* getVoxels() { return &_voxels; } @@ -259,10 +261,10 @@ private: void updateAvatarCollisions(float deltaTime); void updateArmIKAndConstraints( float deltaTime ); void updateCollisionWithSphere( glm::vec3 position, float radius, float deltaTime ); - void updateCollisionWithEnvironment(); - void updateCollisionWithVoxels(); + void updateCollisionWithEnvironment(float deltaTime); + void updateCollisionWithVoxels(float deltaTime); void applyHardCollision(const glm::vec3& penetration, float elasticity, float damping); - void createCollisionSound(const glm::vec3& penetration, float frequency); + void updateCollisionSound(const glm::vec3& penetration, float deltaTime, float frequency); void applyCollisionWithOtherAvatar( Avatar * other, float deltaTime ); void checkForMouseRayTouching(); }; diff --git a/interface/src/Util.cpp b/interface/src/Util.cpp index 65a277b623..ddce092896 100644 --- a/interface/src/Util.cpp +++ b/interface/src/Util.cpp @@ -326,22 +326,38 @@ void drawvec3(int x, int y, float scale, float rotate, float thick, int mono, gl glPopMatrix(); } +void renderCollisionOverlay(int width, int height, float magnitude) { + const float MIN_VISIBLE_COLLISION = 0.01f; + if (magnitude > MIN_VISIBLE_COLLISION) { + glColor4f(0, 0, 0, magnitude); + glBegin(GL_QUADS); + glVertex2f(0, 0); + glVertex2d(width, 0); + glVertex2d(width, height); + glVertex2d(0, height); + glEnd(); + } +} -void drawGroundPlaneGrid(float size) { - glColor3f(0.4f, 0.5f, 0.3f); +void renderGroundPlaneGrid(float size, float impact) { glLineWidth(2.0); - + glm::vec4 impactColor(1, 0, 0, 1); + glm::vec3 lineColor(0.4, 0.5, 0.3); + glm::vec4 surfaceColor(0.5, 0.5, 0.5, 0.4); + + glColor3fv(&lineColor.x); for (float x = 0; x <= size; x++) { glBegin(GL_LINES); - glVertex3f(x, 0.0f, 0); - glVertex3f(x, 0.0f, size); - glVertex3f(0, 0.0f, x); - glVertex3f(size, 0.0f, x); + glVertex3f(x, 0, 0); + glVertex3f(x, 0, size); + glVertex3f(0, 0, x); + glVertex3f(size, 0, x); glEnd(); } - // Draw a translucent quad just underneath the grid. - glColor4f(0.5, 0.5, 0.5, 0.4); + // Draw the floor, colored for recent impact + glm::vec4 floorColor = impact * impactColor + (1.f - impact) * surfaceColor; + glColor4fv(&floorColor.x); glBegin(GL_QUADS); glVertex3f(0, 0, 0); glVertex3f(size, 0, 0); diff --git a/interface/src/Util.h b/interface/src/Util.h index 37bd0595ec..8bc77a98ea 100644 --- a/interface/src/Util.h +++ b/interface/src/Util.h @@ -57,7 +57,10 @@ glm::quat safeMix(const glm::quat& q1, const glm::quat& q2, float alpha); double diffclock(timeval *clock1,timeval *clock2); -void drawGroundPlaneGrid(float size); +void renderGroundPlaneGrid(float size, float impact); + +void renderCollisionOverlay(int width, int height, float magnitude); + void renderDiskShadow(glm::vec3 position, glm::vec3 upDirection, float radius, float darkness); From 984332e63804da9c0329c96fcfc301abb0ad6935 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Wed, 17 Jul 2013 09:51:04 -0700 Subject: [PATCH 6/6] fixes per review --- interface/src/Audio.cpp | 8 +++++--- interface/src/Avatar.cpp | 3 ++- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 9f82559512..41090584f3 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -620,13 +620,15 @@ void Audio::addProceduralSounds(int16_t* inputBuffer, const float COLLISION_SOUND_CUTOFF_LEVEL = 0.01f; const float COLLISION_SOUND_MAX_VOLUME = 1000.f; const float UP_MAJOR_FIFTH = powf(1.5f, 4.0f); + const float DOWN_TWO_OCTAVES = 4.f; + const float DOWN_FOUR_OCTAVES = 16.f; float t; if (_collisionSoundMagnitude > COLLISION_SOUND_CUTOFF_LEVEL) { for (int i = 0; i < numSamples; i++) { t = (float) _proceduralEffectSample + (float) i; sample = sinf(t * _collisionSoundFrequency) + - sinf(t * _collisionSoundFrequency / 4.f) + - sinf(t * _collisionSoundFrequency / 16.f * UP_MAJOR_FIFTH); + sinf(t * _collisionSoundFrequency / DOWN_TWO_OCTAVES) + + sinf(t * _collisionSoundFrequency / DOWN_FOUR_OCTAVES * UP_MAJOR_FIFTH); sample *= _collisionSoundMagnitude * COLLISION_SOUND_MAX_VOLUME; inputBuffer[i] += sample; outputLeft[i] += sample; @@ -638,7 +640,7 @@ void Audio::addProceduralSounds(int16_t* inputBuffer, } // -// Starts a collision sound. magnitude is 0-1, with 1 the loudest possible sound. +// Starts a collision sound. magnitude is 0-1, with 1 the loudest possible sound. // void Audio::startCollisionSound(float magnitude, float frequency, float noise, float duration) { _collisionSoundMagnitude = magnitude; diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp index ee613f5758..e92394af22 100755 --- a/interface/src/Avatar.cpp +++ b/interface/src/Avatar.cpp @@ -881,12 +881,13 @@ void Avatar::updateCollisionWithEnvironment(float deltaTime) { const float ENVIRONMENT_SURFACE_ELASTICITY = 1.0f; const float ENVIRONMENT_SURFACE_DAMPING = 0.01; const float ENVIRONMENT_COLLISION_FREQUENCY = 0.05f; + const float VISIBLE_GROUND_COLLISION_VELOCITY = 0.2f; glm::vec3 penetration; if (Application::getInstance()->getEnvironment()->findCapsulePenetration( _position - up * (_pelvisFloatingHeight - radius), _position + up * (_height - _pelvisFloatingHeight - radius), radius, penetration)) { float velocityTowardCollision = glm::dot(_velocity, glm::normalize(penetration)); - if (velocityTowardCollision > 0.2) { + if (velocityTowardCollision > VISIBLE_GROUND_COLLISION_VELOCITY) { Application::getInstance()->setGroundPlaneImpact(1.0f); } updateCollisionSound(penetration, deltaTime, ENVIRONMENT_COLLISION_FREQUENCY);