From 13b729d9b46111e064f6c1e1ac5bd126065815e6 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Thu, 20 Jun 2013 18:49:05 -0700 Subject: [PATCH] Fixed problems with ring buffer not handling stereo right, reset audio buffers on spacebar. --- interface/src/Application.cpp | 1 + interface/src/Audio.cpp | 50 ++++++++++++++-------- interface/src/Audio.h | 1 + interface/src/Avatar.cpp | 12 +++++- interface/src/Balls.cpp | 57 +++++++++++++++++-------- interface/src/Balls.h | 13 +++--- libraries/audio/src/AudioRingBuffer.cpp | 6 +++ libraries/audio/src/AudioRingBuffer.h | 6 ++- 8 files changed, 101 insertions(+), 45 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 9daab8e42f..65cde3c7be 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -537,6 +537,7 @@ void Application::keyPressEvent(QKeyEvent* event) { case Qt::Key_Space: resetSensors(); + _audio.reset(); break; case Qt::Key_G: diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index f8c0b65038..fd72826dfb 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -28,7 +28,7 @@ // Uncomment the following definition to test audio device latency by copying output to input //#define TEST_AUDIO_LOOPBACK - +//#define SHOW_AUDIO_DEBUG #define VISUALIZE_ECHO_CANCELLATION @@ -152,41 +152,50 @@ inline void Audio::performIO(int16_t* inputLeft, int16_t* outputLeft, int16_t* o AudioRingBuffer* ringBuffer = &_ringBuffer; - // if we've been reset, and there isn't any new packets yet - // just play some silence + // if there is anything in the ring buffer, decide what to do: if (ringBuffer->getEndOfLastWrite()) { - if (!ringBuffer->isStarted() && ringBuffer->diffLastWriteNextOutput() < (PACKET_LENGTH_SAMPLES + _jitterBufferSamples)) { + if (!ringBuffer->isStarted() && ringBuffer->diffLastWriteNextOutput() < (PACKET_LENGTH_SAMPLES + _jitterBufferSamples * (ringBuffer->isStereo() ? 2 : 1))) { // // If not enough audio has arrived to start playback, keep waiting // - //printLog("Held back, buffer has %d of %d samples required.\n", - // ringBuffer->diffLastWriteNextOutput(), - // PACKET_LENGTH_SAMPLES + parentAudio->_jitterBufferSamples); - } else if (ringBuffer->diffLastWriteNextOutput() < PACKET_LENGTH_SAMPLES) { +#ifdef SHOW_AUDIO_DEBUG + printLog("%i,%i,%i,%i\n", + _packetsReceivedThisPlayback, + ringBuffer->diffLastWriteNextOutput(), + PACKET_LENGTH_SAMPLES, + _jitterBufferSamples); +#endif + } else if (ringBuffer->isStarted() && (ringBuffer->diffLastWriteNextOutput() + < PACKET_LENGTH_SAMPLES * (ringBuffer->isStereo() ? 2 : 1))) { // - // If we have run out of audio to send to the audio device, we have starved, - // so reset the ring buffer and packet counters. + // If we have started and now have run out of audio to send to the audio device, + // this means we've starved and should restart. // ringBuffer->setStarted(false); _numStarves++; _packetsReceivedThisPlayback = 0; - - //printLog("Starved, remaining buffer msecs = %.0f\n", - // ringBuffer->diffLastWriteNextOutput() / PACKET_LENGTH_SAMPLES * AUDIO_CALLBACK_MSECS); - _wasStarved = 10; // Frames to render the indication that the system was starved. + _wasStarved = 10; // Frames for which to render the indication that the system was starved. +#ifdef SHOW_AUDIO_DEBUG + printLog("Starved, remaining samples = %.0f\n", + ringBuffer->diffLastWriteNextOutput()); +#endif + } else { // // We are either already playing back, or we have enough audio to start playing back. // if (!ringBuffer->isStarted()) { ringBuffer->setStarted(true); - //printLog("starting playback %0.1f msecs delayed, jitter = %d, pkts recvd: %d \n", - // (usecTimestampNow() - usecTimestamp(&parentAudio->_firstPacketReceivedTime))/1000.0, - // parentAudio->_jitterBufferSamples, - // parentAudio->_packetsReceivedThisPlayback); +#ifdef SHOW_AUDIO_DEBUG + printLog("starting playback %0.1f msecs delayed, jitter = %d, pkts recvd: %d \n", + (usecTimestampNow() - usecTimestamp(&_firstPacketReceivedTime))/1000.0, + _jitterBufferSamples, + _packetsReceivedThisPlayback); +#endif } + // // play whatever we have in the audio buffer // @@ -313,6 +322,11 @@ static void outputPortAudioError(PaError error) { } } +void Audio::reset() { + _packetsReceivedThisPlayback = 0; + _ringBuffer.reset(); +} + Audio::Audio(Oscilloscope* scope, int16_t initialJitterBufferSamples) : _stream(NULL), _ringBuffer(true), diff --git a/interface/src/Audio.h b/interface/src/Audio.h index 09ff961f7d..1e2c69616f 100644 --- a/interface/src/Audio.h +++ b/interface/src/Audio.h @@ -33,6 +33,7 @@ public: Audio(Oscilloscope* scope, int16_t initialJitterBufferSamples); ~Audio(); + void reset(); void render(int screenWidth, int screenHeight); void addReceivedAudioToBuffer(unsigned char* receivedData, int receivedBytes); diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp index d659a5efdb..5588fef328 100644 --- a/interface/src/Avatar.cpp +++ b/interface/src/Avatar.cpp @@ -443,7 +443,16 @@ void Avatar::simulate(float deltaTime, Transmitter* transmitter) { } // update balls - if (_balls) { _balls->simulate(deltaTime); } + if (_balls) { + _balls->moveOrigin(_position); + glm::vec3 lookAt = _head.getLookAtPosition(); + if (glm::length(lookAt) > EPSILON) { + _balls->moveOrigin(lookAt); + } else { + _balls->moveOrigin(_position); + } + _balls->simulate(deltaTime); + } // update torso rotation based on head lean _skeleton.joint[AVATAR_JOINT_TORSO].rotation = glm::quat(glm::radians(glm::vec3( @@ -978,7 +987,6 @@ void Avatar::render(bool lookingInMirror, bool renderAvatarBalls) { // Render the balls if (_balls) { glPushMatrix(); - glTranslatef(_position.x, _position.y, _position.z); _balls->render(); glPopMatrix(); } diff --git a/interface/src/Balls.cpp b/interface/src/Balls.cpp index 5f88ff512f..49932c84ce 100644 --- a/interface/src/Balls.cpp +++ b/interface/src/Balls.cpp @@ -7,36 +7,55 @@ // A cloud of spring-mass spheres to simulate the avatar body/skin. Each ball // connects to as many as 4 neighbors, and executes motion according to a damped // spring, while responding physically to other avatars. -// +// +#include +#include "Util.h" +#include "sharedUtil.h" +#include "world.h" +#include "InterfaceConfig.h" #include "Balls.h" +const float INITIAL_AREA = 0.2f; +const float BALL_RADIUS = 0.025f; +const glm::vec3 INITIAL_COLOR(0.62f, 0.74f, 0.91f); + Balls::Balls(int numberOfBalls) { _numberOfBalls = numberOfBalls; _balls = new Ball[_numberOfBalls]; for (unsigned int i = 0; i < _numberOfBalls; ++i) { - _balls[i].position = glm::vec3(1.0 + randFloat() * 0.5, - 0.5 + randFloat() * 0.5, - 1.0 + randFloat() * 0.5); - _balls[i].radius = 0.02 + randFloat() * 0.06; + _balls[i].position = randVector() * INITIAL_AREA; + _balls[i].targetPosition = _balls[i].position; + _balls[i].velocity = glm::vec3(0, 0, 0); + _balls[i].radius = BALL_RADIUS; for (unsigned int j = 0; j < NUMBER_SPRINGS; ++j) { - _balls[i].links[j] = rand() % (numberOfBalls + 1); - if (_balls[i].links[j]-1 == i) { _balls[i].links[j] = 0; } - _balls[i].springLength[j] = 0.5; - } + _balls[i].links[j] = NULL; + } + } + _color = INITIAL_COLOR; + _origin = glm::vec3(0, 0, 0); +} + +void Balls::moveOrigin(const glm::vec3& newOrigin) { + glm::vec3 delta = newOrigin - _origin; + if (glm::length(delta) > EPSILON) { + _origin = newOrigin; + for (unsigned int i = 0; i < _numberOfBalls; ++i) { + _balls[i].targetPosition += delta; + } } } -const bool RENDER_SPRINGS = true; +const bool RENDER_SPRINGS = false; void Balls::render() { // Render Balls NOTE: This needs to become something other that GlutSpheres! - glColor3f(0.62,0.74,0.91); + glColor3fv(&_color.x); for (unsigned int i = 0; i < _numberOfBalls; ++i) { glPushMatrix(); glTranslatef(_balls[i].position.x, _balls[i].position.y, _balls[i].position.z); - glutSolidSphere(_balls[i].radius, 15, 15); + glutSolidSphere(_balls[i].radius, 8, 8); glPopMatrix(); } @@ -71,18 +90,22 @@ void Balls::simulate(float deltaTime) { // Move particles _balls[i].position += _balls[i].velocity * deltaTime; + _balls[i].targetPosition += _balls[i].velocity * deltaTime; // Drag: decay velocity _balls[i].velocity *= (1.f - CONSTANT_VELOCITY_DAMPING * deltaTime); // Add noise - _balls[i].velocity += glm::vec3((randFloat() - 0.5) * NOISE_SCALE, - (randFloat() - 0.5) * NOISE_SCALE, - (randFloat() - 0.5) * NOISE_SCALE); + _balls[i].velocity += randVector() * NOISE_SCALE; + // Approach target position + for (unsigned int i = 0; i < _numberOfBalls; ++i) { + _balls[i].position += randFloat() * deltaTime * (_balls[i].targetPosition - _balls[i].position); + } + // Spring Force - + /* for (unsigned int j = 0; j < NUMBER_SPRINGS; ++j) { if(_balls[i].links[j] > 0) { float separation = glm::distance(_balls[i].position, @@ -96,7 +119,7 @@ void Balls::simulate(float deltaTime) { //_balls[i].velocity *= (1.f - SPRING_DAMPING*deltaTime); } - } + } */ diff --git a/interface/src/Balls.h b/interface/src/Balls.h index 653854a0c6..440f340307 100644 --- a/interface/src/Balls.h +++ b/interface/src/Balls.h @@ -9,12 +9,6 @@ #ifndef hifi_Balls_h #define hifi_Balls_h -#include -#include "Util.h" -#include "world.h" -#include "InterfaceConfig.h" - - const int NUMBER_SPRINGS = 4; class Balls { @@ -24,14 +18,19 @@ public: void simulate(float deltaTime); void render(); + void setColor(const glm::vec3& c) { _color = c; }; + void moveOrigin(const glm::vec3& newOrigin); + private: struct Ball { - glm::vec3 position, velocity; + glm::vec3 position, targetPosition, velocity; int links[NUMBER_SPRINGS]; float springLength[NUMBER_SPRINGS]; float radius; } *_balls; int _numberOfBalls; + glm::vec3 _origin; + glm::vec3 _color; }; #endif diff --git a/libraries/audio/src/AudioRingBuffer.cpp b/libraries/audio/src/AudioRingBuffer.cpp index 19af07d600..2d396439aa 100644 --- a/libraries/audio/src/AudioRingBuffer.cpp +++ b/libraries/audio/src/AudioRingBuffer.cpp @@ -27,6 +27,12 @@ AudioRingBuffer::~AudioRingBuffer() { delete[] _buffer; } +void AudioRingBuffer::reset() { + _endOfLastWrite = _buffer; + _nextOutput = _buffer; + _isStarted = false; +} + int AudioRingBuffer::parseData(unsigned char* sourceBuffer, int numBytes) { return parseAudioSamples(sourceBuffer + sizeof(PACKET_HEADER_MIXED_AUDIO), numBytes - sizeof(PACKET_HEADER_MIXED_AUDIO)); } diff --git a/libraries/audio/src/AudioRingBuffer.h b/libraries/audio/src/AudioRingBuffer.h index a3c6e59594..4a86e1242b 100644 --- a/libraries/audio/src/AudioRingBuffer.h +++ b/libraries/audio/src/AudioRingBuffer.h @@ -30,6 +30,7 @@ public: AudioRingBuffer(bool isStereo); ~AudioRingBuffer(); + void reset(); int parseData(unsigned char* sourceBuffer, int numBytes); int parseAudioSamples(unsigned char* sourceBuffer, int numBytes); @@ -44,8 +45,11 @@ public: bool isStarted() const { return _isStarted; } void setStarted(bool isStarted) { _isStarted = isStarted; } - + int diffLastWriteNextOutput() const; + + bool isStereo() const { return _isStereo; } + protected: // disallow copying of AudioRingBuffer objects AudioRingBuffer(const AudioRingBuffer&);