rework audio-mixer to use orientations sent by clients

This commit is contained in:
Stephen Birarda 2013-06-04 15:18:05 -07:00
parent 0f70c9c06b
commit cd79339670
3 changed files with 41 additions and 70 deletions

View file

@ -18,6 +18,7 @@
#include <signal.h>
#include <glm/gtx/norm.hpp>
#include <glm/gtx/vector_angle.hpp>
#include <AgentList.h>
#include <Agent.h>
#include <AgentTypes.h>
@ -147,14 +148,16 @@ int main(int argc, const char* argv[]) {
float weakChannelAmplitudeRatio = 1.0f;
if (otherAgent != agent) {
glm::vec3 agentPosition = agentRingBuffer->getPosition();
glm::vec3 otherAgentPosition = otherAgentBuffer->getPosition();
float distanceSquareToSource = glm::distance2(agentPosition, otherAgentPosition);
glm::vec3 listenerPosition = agentRingBuffer->getPosition();
glm::vec3 relativePosition = otherAgentBuffer->getPosition() - agentRingBuffer->getPosition();
glm::vec3 rotatedSourcePosition = glm::inverse(agentRingBuffer->getOrientation())
* relativePosition;
float distanceSquareToSource = glm::dot(relativePosition, relativePosition);
float distanceCoefficient = 1.0f;
float offAxisCoefficient = 1.0f;
if (otherAgentBuffer->getRadius() == 0
|| (distanceSquareToSource > (otherAgentBuffer->getRadius()
* otherAgentBuffer->getRadius()))) {
@ -167,17 +170,17 @@ int main(int argc, const char* argv[]) {
// multiply the normalized vector between the center of the sphere
// and the position of the source by the radius to get the
// closest point on the boundary of the sphere to the source
glm::vec3 difference = agentPosition - otherAgentPosition;
glm::vec3 closestPoint = glm::normalize(difference) * otherAgentBuffer->getRadius();
glm::vec3 closestPoint = glm::normalize(relativePosition) * otherAgentBuffer->getRadius();
// for the other calculations the agent position is the closest point on the sphere
otherAgentPosition = closestPoint;
rotatedSourcePosition = closestPoint;
// ovveride the distance to the agent with the distance to the point on the
// boundary of the sphere
distanceSquareToSource = glm::distance2(agentPosition, closestPoint);
distanceSquareToSource = glm::distance2(listenerPosition, closestPoint);
}
const float DISTANCE_SCALE = 2.5f;
const float GEOMETRIC_AMPLITUDE_SCALAR = 0.3f;
const float DISTANCE_LOG_BASE = 2.5f;
@ -188,67 +191,40 @@ int main(int argc, const char* argv[]) {
DISTANCE_SCALE_LOG +
(logf(distanceSquareToSource) / logf(DISTANCE_LOG_BASE)) - 1);
distanceCoefficient = std::min(1.0f, distanceCoefficient);
// off-axis attenuation and spatialization of audio
// not performed if listener is inside spherical injector
// get the angle from the right-angle triangle
float triangleAngle = atan2f(fabsf(agentPosition.z - otherAgentPosition.z),
fabsf(agentPosition.x - otherAgentPosition.x)) * (180 / M_PI);
float absoluteAngleToSource = 0;
// calculate the angle from the source to the listener
bearingRelativeAngleToSource = glm::orientedAngle(glm::vec3(0.0f, 0.0f, -1.0f),
glm::normalize(rotatedSourcePosition),
glm::vec3(0.0f, 1.0f, 0.0f));
// find the angle we need for calculation based on the orientation of the triangle
if (otherAgentPosition.x > agentPosition.x) {
if (otherAgentPosition.z > agentPosition.z) {
absoluteAngleToSource = -90 + triangleAngle;
} else {
absoluteAngleToSource = -90 - triangleAngle;
}
} else {
if (otherAgentPosition.z > agentPosition.z) {
absoluteAngleToSource = 90 - triangleAngle;
} else {
absoluteAngleToSource = 90 + triangleAngle;
}
}
bearingRelativeAngleToSource = absoluteAngleToSource - agentRingBuffer->getBearing();
if (bearingRelativeAngleToSource > 180) {
bearingRelativeAngleToSource -= 360;
} else if (bearingRelativeAngleToSource < -180) {
bearingRelativeAngleToSource += 360;
}
float angleOfDelivery = absoluteAngleToSource - otherAgentBuffer->getBearing();
if (angleOfDelivery > 180) {
angleOfDelivery -= 360;
} else if (angleOfDelivery < -180) {
angleOfDelivery += 360;
}
// calculate the angle delivery
glm::vec3 rotatedListenerPosition = glm::inverse(otherAgentBuffer->getOrientation())
* relativePosition;
float angleOfDelivery = glm::angle(glm::vec3(0.0f, 0.0f, 1.0f),
glm::normalize(rotatedListenerPosition));
offAxisCoefficient = MAX_OFF_AXIS_ATTENUATION
+ (OFF_AXIS_ATTENUATION_FORMULA_STEP * (fabsf(angleOfDelivery) / 90.0f));
bearingRelativeAngleToSource *= (M_PI / 180);
float sinRatio = fabsf(sinf(glm::radians(bearingRelativeAngleToSource)));
numSamplesDelay = PHASE_DELAY_AT_90 * sinRatio;
weakChannelAmplitudeRatio = 1 - (PHASE_AMPLITUDE_RATIO_AT_90 * sinRatio);
}
attenuationCoefficient = distanceCoefficient
* otherAgentBuffer->getAttenuationRatio()
* offAxisCoefficient;
float sinRatio = fabsf(sinf(bearingRelativeAngleToSource));
numSamplesDelay = PHASE_DELAY_AT_90 * sinRatio;
weakChannelAmplitudeRatio = 1 - (PHASE_AMPLITUDE_RATIO_AT_90 * sinRatio);
}
int16_t* goodChannel = bearingRelativeAngleToSource > 0.0f
? clientSamples + BUFFER_LENGTH_SAMPLES_PER_CHANNEL
: clientSamples;
int16_t* delayedChannel = bearingRelativeAngleToSource > 0.0f
? clientSamples
: clientSamples + BUFFER_LENGTH_SAMPLES_PER_CHANNEL;
int16_t* delayedChannel = bearingRelativeAngleToSource > 0.0f
? clientSamples + BUFFER_LENGTH_SAMPLES_PER_CHANNEL
: clientSamples;
int16_t* delaySamplePointer = otherAgentBuffer->getNextOutput() == otherAgentBuffer->getBuffer()
? otherAgentBuffer->getBuffer() + RING_BUFFER_SAMPLES - numSamplesDelay
@ -307,7 +283,7 @@ int main(int argc, const char* argv[]) {
agentList->updateAgentWithData(agentAddress, packetData, receivedBytes);
if (std::isnan(((AudioRingBuffer *)avatarAgent->getLinkedData())->getBearing())) {
if (std::isnan(((AudioRingBuffer *)avatarAgent->getLinkedData())->getOrientation().x)) {
// kill off this agent - temporary solution to mixer crash on mac sleep
avatarAgent->setAlive(false);
}

View file

@ -65,23 +65,16 @@ int AudioRingBuffer::parseData(unsigned char* sourceBuffer, int numBytes) {
unsigned int attenuationByte = *(dataBuffer++);
_attenuationRatio = attenuationByte / 255.0f;
memcpy(&_bearing, dataBuffer, sizeof(float));
dataBuffer += sizeof(_bearing);
memcpy(&_orientation, dataBuffer, sizeof(_orientation));
dataBuffer += sizeof(_orientation);
// if this agent sent us a NaN bearing then don't consider this good audio and bail
if (std::isnan(_bearing)) {
// if this agent sent us a NaN for first float in orientation then don't consider this good audio and bail
if (std::isnan(_orientation.x)) {
_endOfLastWrite = _nextOutput = _buffer;
_started = false;
return 0;
} else if (_bearing > 180 || _bearing < -180) {
// we were passed an invalid bearing because this agent wants loopback (pressed the H key)
_shouldLoopbackForAgent = true;
// correct the bearing
_bearing = _bearing > 0
? _bearing - AGENT_LOOPBACK_MODIFIER
: _bearing + AGENT_LOOPBACK_MODIFIER;
} else {
// currently no possiblity for loopback, need to add once quaternion audio is working again
_shouldLoopbackForAgent = false;
}
}

View file

@ -12,6 +12,7 @@
#include <stdint.h>
#include <glm/glm.hpp>
#include <glm/gtx/quaternion.hpp>
#include "AgentData.h"
@ -44,8 +45,9 @@ public:
void setShouldBeAddedToMix(bool shouldBeAddedToMix) { _shouldBeAddedToMix = shouldBeAddedToMix; }
const glm::vec3& getPosition() const { return _position; }
const glm::quat& getOrientation() const { return _orientation; }
float getAttenuationRatio() const { return _attenuationRatio; }
float getBearing() const { return _bearing; }
bool shouldLoopbackForAgent() const { return _shouldLoopbackForAgent; }
const unsigned char* getStreamIdentifier() const { return _streamIdentifier; }
@ -58,9 +60,9 @@ private:
int _ringBufferLengthSamples;
int _bufferLengthSamples;
glm::vec3 _position;
glm::quat _orientation;
float _radius;
float _attenuationRatio;
float _bearing;
int16_t* _nextOutput;
int16_t* _endOfLastWrite;
int16_t* _buffer;