mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-04-09 05:32:46 +02:00
Fixed problems with ring buffer not handling stereo right, reset audio buffers on spacebar.
This commit is contained in:
parent
56b8a5880d
commit
13b729d9b4
8 changed files with 101 additions and 45 deletions
|
@ -537,6 +537,7 @@ void Application::keyPressEvent(QKeyEvent* event) {
|
|||
|
||||
case Qt::Key_Space:
|
||||
resetSensors();
|
||||
_audio.reset();
|
||||
break;
|
||||
|
||||
case Qt::Key_G:
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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 <glm/glm.hpp>
|
||||
#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);
|
||||
|
||||
}
|
||||
}
|
||||
} */
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -9,12 +9,6 @@
|
|||
#ifndef hifi_Balls_h
|
||||
#define hifi_Balls_h
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#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
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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&);
|
||||
|
|
Loading…
Reference in a new issue