From f3ce68e5e4c40c34e67db5e4195a3a99b9207f84 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 3 Jun 2013 12:21:44 -0700 Subject: [PATCH 01/16] remove space at the top of PacketHeaders --- libraries/shared/src/PacketHeaders.h | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/shared/src/PacketHeaders.h b/libraries/shared/src/PacketHeaders.h index 850eced59b..ea9f5f9fcf 100644 --- a/libraries/shared/src/PacketHeaders.h +++ b/libraries/shared/src/PacketHeaders.h @@ -1,4 +1,3 @@ - // // PacketHeaders.h // hifi From c55b6a20d77de398351e6d3d0982f5f4b92b4295 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 3 Jun 2013 15:38:12 -0700 Subject: [PATCH 02/16] parse the desired cube side length for injected audio source --- injector/src/main.cpp | 15 +++++++++++++-- libraries/audio/src/AudioInjector.cpp | 13 ++++++++++++- libraries/audio/src/AudioInjector.h | 4 ++++ libraries/audio/src/AudioRingBuffer.cpp | 11 +++++++++++ libraries/audio/src/AudioRingBuffer.h | 4 ++++ 5 files changed, 44 insertions(+), 3 deletions(-) diff --git a/injector/src/main.cpp b/injector/src/main.cpp index 32a8442d8f..512882c374 100644 --- a/injector/src/main.cpp +++ b/injector/src/main.cpp @@ -32,10 +32,11 @@ bool loopAudio = true; float sleepIntervalMin = 1.00; float sleepIntervalMax = 2.00; char *sourceAudioFile = NULL; -const char *allowedParameters = ":rb::t::c::a::f::d:"; +const char *allowedParameters = ":rb::t::c::a::f::d::s:"; float floatArguments[4] = {0.0f, 0.0f, 0.0f, 0.0f}; unsigned char volume = DEFAULT_INJECTOR_VOLUME; -float triggerDistance = 0; +float triggerDistance = 0.0f; +float cubeSideLength = 0.0f; void usage(void) { std::cout << "High Fidelity - Interface audio injector" << std::endl; @@ -46,6 +47,7 @@ void usage(void) { std::cout << " -a 0-255 Attenuation curve modifier, defaults to 255" << std::endl; std::cout << " -f FILENAME Name of audio source file. Required - RAW format, 22050hz 16bit signed mono" << std::endl; std::cout << " -d FLOAT Trigger distance for injection. If not specified will loop constantly" << std::endl; + std::cout << " -s FLOAT Length of side of cube audio source. If not specified injected audio is point source" << std::endl; } bool processParameters(int parameterCount, char* parameterData[]) { @@ -92,6 +94,10 @@ bool processParameters(int parameterCount, char* parameterData[]) { ::triggerDistance = atof(optarg); std::cout << "[DEBUG] Trigger distance: " << optarg << std::endl; break; + case 's': + ::cubeSideLength = atof(optarg); + std::cout << "[DEBUG] Cube side length: " << optarg << std::endl; + break; default: usage(); return false; @@ -163,6 +169,11 @@ int main(int argc, char* argv[]) { injector.setPosition(glm::vec3(::floatArguments[0], ::floatArguments[1], ::floatArguments[2])); injector.setBearing(*(::floatArguments + 3)); injector.setVolume(::volume); + + if (::cubeSideLength > 0) { + // if we were passed a cube side length, give that to the injector + injector.setCubeSideLength(::cubeSideLength); + } // register the callback for agent data creation agentList->linkedDataCreateCallback = createAvatarDataForAgent; diff --git a/libraries/audio/src/AudioInjector.cpp b/libraries/audio/src/AudioInjector.cpp index 8e540c9735..e1de27ef6d 100644 --- a/libraries/audio/src/AudioInjector.cpp +++ b/libraries/audio/src/AudioInjector.cpp @@ -19,6 +19,7 @@ const int MAX_INJECTOR_VOLUME = 0xFF; AudioInjector::AudioInjector(const char* filename) : _position(), + _cubeSideLength(0.0f), _bearing(0), _volume(MAX_INJECTOR_VOLUME), _indexOfNextSlot(0), @@ -48,6 +49,7 @@ AudioInjector::AudioInjector(const char* filename) : AudioInjector::AudioInjector(int maxNumSamples) : _numTotalSamples(maxNumSamples), _position(), + _cubeSideLength(0.0f), _bearing(0), _volume(MAX_INJECTOR_VOLUME), _indexOfNextSlot(0), @@ -75,7 +77,9 @@ void AudioInjector::injectAudio(UDPSocket* injectorSocket, sockaddr* destination unsigned char dataPacket[BUFFER_LENGTH_BYTES + leadingBytes]; dataPacket[0] = PACKET_HEADER_INJECT_AUDIO; - unsigned char *currentPacketPtr = dataPacket + 1; + // add the correct command for point source or cube of sound + dataPacket[1] = (_cubeSideLength > 0) ? INJECT_AUDIO_AT_CUBE_COMMAND : INJECT_AUDIO_AT_POINT_COMMAND; + unsigned char *currentPacketPtr = dataPacket + sizeof(PACKET_HEADER) + sizeof(INJECT_AUDIO_AT_POINT_COMMAND); // copy the identifier for this injector memcpy(currentPacketPtr, &_streamIdentifier, sizeof(_streamIdentifier)); @@ -84,6 +88,13 @@ void AudioInjector::injectAudio(UDPSocket* injectorSocket, sockaddr* destination memcpy(currentPacketPtr, &_position, sizeof(_position)); currentPacketPtr += sizeof(_position); + if (_cubeSideLength > 0) { + // if we have a cube half height we need to send it here + // this tells the mixer how much volume the injected audio will occupy + memcpy(currentPacketPtr, &_cubeSideLength, sizeof(_cubeSideLength)); + currentPacketPtr += sizeof(_cubeSideLength); + } + *currentPacketPtr = _volume; currentPacketPtr++; diff --git a/libraries/audio/src/AudioInjector.h b/libraries/audio/src/AudioInjector.h index 7db9398fc9..0269931568 100644 --- a/libraries/audio/src/AudioInjector.h +++ b/libraries/audio/src/AudioInjector.h @@ -39,6 +39,9 @@ public: float getBearing() const { return _bearing; } void setBearing(float bearing) { _bearing = bearing; } + float getCubeSideLength() const { return _cubeSideLength; } + void setCubeSideLength(float cubeSideLength) { _cubeSideLength = cubeSideLength; } + void addSample(const int16_t sample); void addSamples(int16_t* sampleBuffer, int numSamples); private: @@ -46,6 +49,7 @@ private: int16_t* _audioSampleArray; int _numTotalSamples; glm::vec3 _position; + float _cubeSideLength; float _bearing; unsigned char _volume; int _indexOfNextSlot; diff --git a/libraries/audio/src/AudioRingBuffer.cpp b/libraries/audio/src/AudioRingBuffer.cpp index 006dd825bf..39cdc43287 100644 --- a/libraries/audio/src/AudioRingBuffer.cpp +++ b/libraries/audio/src/AudioRingBuffer.cpp @@ -17,6 +17,7 @@ AudioRingBuffer::AudioRingBuffer(int ringSamples, int bufferSamples) : AgentData(NULL), _ringBufferLengthSamples(ringSamples), _bufferLengthSamples(bufferSamples), + _cubeSideLength(0.0f), _endOfLastWrite(NULL), _started(false), _shouldBeAddedToMix(false), @@ -46,11 +47,21 @@ int AudioRingBuffer::parseData(unsigned char* sourceBuffer, int numBytes) { // we've got a stream identifier to pull from the packet memcpy(&_streamIdentifier, dataBuffer, sizeof(_streamIdentifier)); dataBuffer += sizeof(_streamIdentifier); + + // push past the injection command + dataBuffer += sizeof(INJECT_AUDIO_AT_POINT_COMMAND); } memcpy(&_position, dataBuffer, sizeof(_position)); dataBuffer += (sizeof(_position)); + if (sourceBuffer[0] == PACKET_HEADER_INJECT_AUDIO && sourceBuffer[1] == INJECT_AUDIO_AT_CUBE_COMMAND) { + // this is audio that needs to be injected as a volume (cube) + // parse out the cubeHalfHeight sent by the client + memcpy(&_cubeSideLength, dataBuffer, sizeof(_cubeSideLength)); + dataBuffer += (sizeof(_cubeSideLength)); + } + unsigned int attenuationByte = *(dataBuffer++); _attenuationRatio = attenuationByte / 255.0f; diff --git a/libraries/audio/src/AudioRingBuffer.h b/libraries/audio/src/AudioRingBuffer.h index b448f93cee..3554e13d46 100644 --- a/libraries/audio/src/AudioRingBuffer.h +++ b/libraries/audio/src/AudioRingBuffer.h @@ -17,6 +17,9 @@ const int STREAM_IDENTIFIER_NUM_BYTES = 8; +const char INJECT_AUDIO_AT_POINT_COMMAND = 'P'; +const char INJECT_AUDIO_AT_CUBE_COMMAND = 'C'; + class AudioRingBuffer : public AgentData { public: AudioRingBuffer(int ringSamples, int bufferSamples); @@ -53,6 +56,7 @@ private: int _ringBufferLengthSamples; int _bufferLengthSamples; glm::vec3 _position; + float _cubeSideLength; float _attenuationRatio; float _bearing; int16_t* _nextOutput; From 3f7fbb5c1ee97e4c536b8f28a529a4fece8b914a Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 4 Jun 2013 10:57:53 -0700 Subject: [PATCH 03/16] change injector from cube to sphere --- audio-mixer/src/main.cpp | 138 +++++++++++++++--------- injector/src/main.cpp | 18 ++-- libraries/audio/src/AudioInjector.cpp | 20 ++-- libraries/audio/src/AudioInjector.h | 6 +- libraries/audio/src/AudioRingBuffer.cpp | 8 +- libraries/audio/src/AudioRingBuffer.h | 4 +- 6 files changed, 117 insertions(+), 77 deletions(-) diff --git a/audio-mixer/src/main.cpp b/audio-mixer/src/main.cpp index 982ebc526c..d94a1d59d6 100644 --- a/audio-mixer/src/main.cpp +++ b/audio-mixer/src/main.cpp @@ -160,68 +160,100 @@ int main(int argc, const char* argv[]) { int lowAgentIndex = std::min(agent.getAgentIndex(), otherAgent.getAgentIndex()); int highAgentIndex = std::max(agent.getAgentIndex(), otherAgent.getAgentIndex()); + bool insideSphericalInjector = false; + if (distanceCoefficients[lowAgentIndex][highAgentIndex] == 0) { - float distanceToAgent = sqrtf(powf(agentPosition.x - otherAgentPosition.x, 2) + - powf(agentPosition.y - otherAgentPosition.y, 2) + - powf(agentPosition.z - otherAgentPosition.z, 2)); + float distanceToAgent = glm::distance(agentPosition, otherAgentPosition); + + float minCoefficient = 1.0f; + + if (otherAgentBuffer->getRadius() == 0 || distanceToAgent > otherAgentBuffer->getRadius()) { + // this is either not a spherical source, or the listener is outside the sphere + + if (otherAgentBuffer->getRadius() > 0) { + // this is a spherical source - the distance used for the coefficient + // needs to be the closest point on the boundary to the source + + // 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(); + + // for the other calculations the agent position is the closest point on the sphere + otherAgentPosition = closestPoint; + + // ovveride the distance to the agent with the distance to the point on the + // boundary of the sphere + distanceToAgent = glm::distance(agentPosition, closestPoint); + } + + // calculate the distance coefficient using the distance to this agent + minCoefficient = std::min(1.0f, + powf(0.3, (logf(DISTANCE_SCALE * distanceToAgent) / + logf(2.5)) - 1)); + } else { + insideSphericalInjector = true; + } + - float minCoefficient = std::min(1.0f, - powf(0.3, - (logf(DISTANCE_SCALE * distanceToAgent) / logf(2.5)) - - 1)); distanceCoefficients[lowAgentIndex][highAgentIndex] = minCoefficient; } - - // 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; - bearingRelativeAngleToSource = 0; - - // 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; + if (!insideSphericalInjector) { + // off-axis attenuation and spatialization of audio is not performed + // if the listener is inside a 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; + bearingRelativeAngleToSource = 0; + + // 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 { - absoluteAngleToSource = -90 - triangleAngle; + 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; + } + + float offAxisCoefficient = MAX_OFF_AXIS_ATTENUATION + + (OFF_AXIS_ATTENUATION_FORMULA_STEP * (fabsf(angleOfDelivery) / 90.0f)); + + attenuationCoefficient = distanceCoefficients[lowAgentIndex][highAgentIndex] + * otherAgentBuffer->getAttenuationRatio() + * offAxisCoefficient; + + bearingRelativeAngleToSource *= (M_PI / 180); + + float sinRatio = fabsf(sinf(bearingRelativeAngleToSource)); + numSamplesDelay = PHASE_DELAY_AT_90 * sinRatio; + weakChannelAmplitudeRatio = 1 - (PHASE_AMPLITUDE_RATIO_AT_90 * sinRatio); } - - 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; - } - - float offAxisCoefficient = MAX_OFF_AXIS_ATTENUATION + - (OFF_AXIS_ATTENUATION_FORMULA_STEP * (fabsf(angleOfDelivery) / 90.0f)); - - attenuationCoefficient = distanceCoefficients[lowAgentIndex][highAgentIndex] - * otherAgentBuffer->getAttenuationRatio() - * offAxisCoefficient; - - bearingRelativeAngleToSource *= (M_PI / 180); - - 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 diff --git a/injector/src/main.cpp b/injector/src/main.cpp index 512882c374..18fa1f27df 100644 --- a/injector/src/main.cpp +++ b/injector/src/main.cpp @@ -36,25 +36,25 @@ const char *allowedParameters = ":rb::t::c::a::f::d::s:"; float floatArguments[4] = {0.0f, 0.0f, 0.0f, 0.0f}; unsigned char volume = DEFAULT_INJECTOR_VOLUME; float triggerDistance = 0.0f; -float cubeSideLength = 0.0f; +float radius = 0.0f; void usage(void) { std::cout << "High Fidelity - Interface audio injector" << std::endl; - std::cout << " -r Random sleep mode. If not specified will default to constant loop." << std::endl; + std::cout << " -s Random sleep mode. If not specified will default to constant loop." << std::endl; std::cout << " -b FLOAT Min. number of seconds to sleep. Only valid in random sleep mode. Default 1.0" << std::endl; std::cout << " -t FLOAT Max. number of seconds to sleep. Only valid in random sleep mode. Default 2.0" << std::endl; std::cout << " -c FLOAT,FLOAT,FLOAT,FLOAT X,Y,Z,YAW position in universe where audio will be originating from and direction. Defaults to 0,0,0,0" << std::endl; std::cout << " -a 0-255 Attenuation curve modifier, defaults to 255" << std::endl; std::cout << " -f FILENAME Name of audio source file. Required - RAW format, 22050hz 16bit signed mono" << std::endl; std::cout << " -d FLOAT Trigger distance for injection. If not specified will loop constantly" << std::endl; - std::cout << " -s FLOAT Length of side of cube audio source. If not specified injected audio is point source" << std::endl; + std::cout << " -r FLOAT Radius for spherical source. If not specified injected audio is point source" << std::endl; } bool processParameters(int parameterCount, char* parameterData[]) { int p; while ((p = getopt(parameterCount, parameterData, allowedParameters)) != -1) { switch (p) { - case 'r': + case 's': ::loopAudio = false; std::cout << "[DEBUG] Random sleep mode enabled" << std::endl; break; @@ -94,9 +94,9 @@ bool processParameters(int parameterCount, char* parameterData[]) { ::triggerDistance = atof(optarg); std::cout << "[DEBUG] Trigger distance: " << optarg << std::endl; break; - case 's': - ::cubeSideLength = atof(optarg); - std::cout << "[DEBUG] Cube side length: " << optarg << std::endl; + case 'r': + ::radius = atof(optarg); + std::cout << "[DEBUG] Injector radius: " << optarg << std::endl; break; default: usage(); @@ -170,9 +170,9 @@ int main(int argc, char* argv[]) { injector.setBearing(*(::floatArguments + 3)); injector.setVolume(::volume); - if (::cubeSideLength > 0) { + if (::radius > 0) { // if we were passed a cube side length, give that to the injector - injector.setCubeSideLength(::cubeSideLength); + injector.setRadius(::radius); } // register the callback for agent data creation diff --git a/libraries/audio/src/AudioInjector.cpp b/libraries/audio/src/AudioInjector.cpp index e1de27ef6d..fbb55a84c3 100644 --- a/libraries/audio/src/AudioInjector.cpp +++ b/libraries/audio/src/AudioInjector.cpp @@ -19,7 +19,7 @@ const int MAX_INJECTOR_VOLUME = 0xFF; AudioInjector::AudioInjector(const char* filename) : _position(), - _cubeSideLength(0.0f), + _radius(0.0f), _bearing(0), _volume(MAX_INJECTOR_VOLUME), _indexOfNextSlot(0), @@ -49,7 +49,7 @@ AudioInjector::AudioInjector(const char* filename) : AudioInjector::AudioInjector(int maxNumSamples) : _numTotalSamples(maxNumSamples), _position(), - _cubeSideLength(0.0f), + _radius(0.0f), _bearing(0), _volume(MAX_INJECTOR_VOLUME), _indexOfNextSlot(0), @@ -72,13 +72,19 @@ void AudioInjector::injectAudio(UDPSocket* injectorSocket, sockaddr* destination timeval startTime; // calculate the number of bytes required for additional data - int leadingBytes = sizeof(PACKET_HEADER) + sizeof(_streamIdentifier) + int leadingBytes = sizeof(PACKET_HEADER) + sizeof(INJECT_AUDIO_AT_POINT_COMMAND) + sizeof(_streamIdentifier) + sizeof(_position) + sizeof(_bearing) + sizeof(_volume); + + if (_radius > 0) { + // we'll need 4 extra bytes if the cube side length is being sent as well + leadingBytes += sizeof(_radius); + } + unsigned char dataPacket[BUFFER_LENGTH_BYTES + leadingBytes]; dataPacket[0] = PACKET_HEADER_INJECT_AUDIO; // add the correct command for point source or cube of sound - dataPacket[1] = (_cubeSideLength > 0) ? INJECT_AUDIO_AT_CUBE_COMMAND : INJECT_AUDIO_AT_POINT_COMMAND; + dataPacket[1] = (_radius > 0) ? INJECT_AUDIO_AT_CUBE_COMMAND : INJECT_AUDIO_AT_POINT_COMMAND; unsigned char *currentPacketPtr = dataPacket + sizeof(PACKET_HEADER) + sizeof(INJECT_AUDIO_AT_POINT_COMMAND); // copy the identifier for this injector @@ -88,11 +94,11 @@ void AudioInjector::injectAudio(UDPSocket* injectorSocket, sockaddr* destination memcpy(currentPacketPtr, &_position, sizeof(_position)); currentPacketPtr += sizeof(_position); - if (_cubeSideLength > 0) { + if (_radius > 0) { // if we have a cube half height we need to send it here // this tells the mixer how much volume the injected audio will occupy - memcpy(currentPacketPtr, &_cubeSideLength, sizeof(_cubeSideLength)); - currentPacketPtr += sizeof(_cubeSideLength); + memcpy(currentPacketPtr, &_radius, sizeof(_radius)); + currentPacketPtr += sizeof(_radius); } *currentPacketPtr = _volume; diff --git a/libraries/audio/src/AudioInjector.h b/libraries/audio/src/AudioInjector.h index 0269931568..d8b907d368 100644 --- a/libraries/audio/src/AudioInjector.h +++ b/libraries/audio/src/AudioInjector.h @@ -39,8 +39,8 @@ public: float getBearing() const { return _bearing; } void setBearing(float bearing) { _bearing = bearing; } - float getCubeSideLength() const { return _cubeSideLength; } - void setCubeSideLength(float cubeSideLength) { _cubeSideLength = cubeSideLength; } + float getRadius() const { return _radius; } + void setRadius(float radius) { _radius = radius; } void addSample(const int16_t sample); void addSamples(int16_t* sampleBuffer, int numSamples); @@ -49,7 +49,7 @@ private: int16_t* _audioSampleArray; int _numTotalSamples; glm::vec3 _position; - float _cubeSideLength; + float _radius; float _bearing; unsigned char _volume; int _indexOfNextSlot; diff --git a/libraries/audio/src/AudioRingBuffer.cpp b/libraries/audio/src/AudioRingBuffer.cpp index 39cdc43287..fe93ece47f 100644 --- a/libraries/audio/src/AudioRingBuffer.cpp +++ b/libraries/audio/src/AudioRingBuffer.cpp @@ -17,7 +17,7 @@ AudioRingBuffer::AudioRingBuffer(int ringSamples, int bufferSamples) : AgentData(NULL), _ringBufferLengthSamples(ringSamples), _bufferLengthSamples(bufferSamples), - _cubeSideLength(0.0f), + _radius(0.0f), _endOfLastWrite(NULL), _started(false), _shouldBeAddedToMix(false), @@ -53,13 +53,13 @@ int AudioRingBuffer::parseData(unsigned char* sourceBuffer, int numBytes) { } memcpy(&_position, dataBuffer, sizeof(_position)); - dataBuffer += (sizeof(_position)); + dataBuffer += sizeof(_position); if (sourceBuffer[0] == PACKET_HEADER_INJECT_AUDIO && sourceBuffer[1] == INJECT_AUDIO_AT_CUBE_COMMAND) { // this is audio that needs to be injected as a volume (cube) // parse out the cubeHalfHeight sent by the client - memcpy(&_cubeSideLength, dataBuffer, sizeof(_cubeSideLength)); - dataBuffer += (sizeof(_cubeSideLength)); + memcpy(&_radius, dataBuffer, sizeof(_radius)); + dataBuffer += sizeof(_radius); } unsigned int attenuationByte = *(dataBuffer++); diff --git a/libraries/audio/src/AudioRingBuffer.h b/libraries/audio/src/AudioRingBuffer.h index 3554e13d46..0a2b8ed7db 100644 --- a/libraries/audio/src/AudioRingBuffer.h +++ b/libraries/audio/src/AudioRingBuffer.h @@ -26,6 +26,8 @@ public: ~AudioRingBuffer(); int parseData(unsigned char* sourceBuffer, int numBytes); + + float getRadius() const { return _radius; } int16_t* getNextOutput() const { return _nextOutput; } void setNextOutput(int16_t* nextOutput) { _nextOutput = nextOutput; } @@ -56,7 +58,7 @@ private: int _ringBufferLengthSamples; int _bufferLengthSamples; glm::vec3 _position; - float _cubeSideLength; + float _radius; float _attenuationRatio; float _bearing; int16_t* _nextOutput; From eaaeedab68f04da5af5323f1f1bfa88aebbb3b75 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 4 Jun 2013 11:24:07 -0700 Subject: [PATCH 04/16] refactor calculations for audio --- audio-mixer/src/main.cpp | 109 ++++++++++++++++++--------------------- injector/src/main.cpp | 2 +- 2 files changed, 50 insertions(+), 61 deletions(-) diff --git a/audio-mixer/src/main.cpp b/audio-mixer/src/main.cpp index d94a1d59d6..bc75ac5698 100644 --- a/audio-mixer/src/main.cpp +++ b/audio-mixer/src/main.cpp @@ -17,6 +17,7 @@ #include #include +#include #include #include #include @@ -55,7 +56,6 @@ const float BUFFER_SEND_INTERVAL_USECS = (BUFFER_LENGTH_SAMPLES_PER_CHANNEL / SA const long MAX_SAMPLE_VALUE = std::numeric_limits::max(); const long MIN_SAMPLE_VALUE = std::numeric_limits::min(); -const float DISTANCE_SCALE = 2.5f; const float PHASE_AMPLITUDE_RATIO_AT_90 = 0.5; const int PHASE_DELAY_AT_90 = 20; @@ -128,10 +128,6 @@ int main(int argc, const char* argv[]) { } } - int numAgents = agentList->size(); - float distanceCoefficients[numAgents][numAgents]; - memset(distanceCoefficients, 0, sizeof(distanceCoefficients)); - for (AgentList::iterator agent = agentList->begin(); agent != agentList->end(); agent++) { if (agent->getType() == AGENT_TYPE_AVATAR) { AudioRingBuffer* agentRingBuffer = (AudioRingBuffer*) agent->getLinkedData(); @@ -146,69 +142,60 @@ int main(int argc, const char* argv[]) { if (otherAgentBuffer->shouldBeAddedToMix()) { float bearingRelativeAngleToSource = 0.f; - float attenuationCoefficient = 1.f; + float attenuationCoefficient = 1.0f; int numSamplesDelay = 0; - float weakChannelAmplitudeRatio = 1.f; + float weakChannelAmplitudeRatio = 1.0f; if (otherAgent != agent) { glm::vec3 agentPosition = agentRingBuffer->getPosition(); glm::vec3 otherAgentPosition = otherAgentBuffer->getPosition(); - // calculate the distance to the other agent + float distanceSquareToSource = glm::distance2(agentPosition, otherAgentPosition); - // use the distance to the other agent to calculate the change in volume for this frame - int lowAgentIndex = std::min(agent.getAgentIndex(), otherAgent.getAgentIndex()); - int highAgentIndex = std::max(agent.getAgentIndex(), otherAgent.getAgentIndex()); + float distanceCoefficient = 1.0f; + float offAxisCoefficient = 1.0f; - bool insideSphericalInjector = false; - - if (distanceCoefficients[lowAgentIndex][highAgentIndex] == 0) { - float distanceToAgent = glm::distance(agentPosition, otherAgentPosition); + if (otherAgentBuffer->getRadius() == 0 + || (distanceSquareToSource > (otherAgentBuffer->getRadius() + * otherAgentBuffer->getRadius()))) { + // this is either not a spherical source, or the listener is outside the sphere - float minCoefficient = 1.0f; - - if (otherAgentBuffer->getRadius() == 0 || distanceToAgent > otherAgentBuffer->getRadius()) { - // this is either not a spherical source, or the listener is outside the sphere + if (otherAgentBuffer->getRadius() > 0) { + // this is a spherical source - the distance used for the coefficient + // needs to be the closest point on the boundary to the source - if (otherAgentBuffer->getRadius() > 0) { - // this is a spherical source - the distance used for the coefficient - // needs to be the closest point on the boundary to the source - - // 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(); - - // for the other calculations the agent position is the closest point on the sphere - otherAgentPosition = closestPoint; - - // ovveride the distance to the agent with the distance to the point on the - // boundary of the sphere - distanceToAgent = glm::distance(agentPosition, closestPoint); - } + // 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(); - // calculate the distance coefficient using the distance to this agent - minCoefficient = std::min(1.0f, - powf(0.3, (logf(DISTANCE_SCALE * distanceToAgent) / - logf(2.5)) - 1)); - } else { - insideSphericalInjector = true; + // for the other calculations the agent position is the closest point on the sphere + otherAgentPosition = closestPoint; + + // ovveride the distance to the agent with the distance to the point on the + // boundary of the sphere + distanceSquareToSource = glm::distance2(agentPosition, closestPoint); } + + const float DISTANCE_SCALE = 2.5f; + const float GEOMETRIC_AMPLITUDE_SCALAR = 0.3f; + const float DISTANCE_LOG_BASE = 2.5f; + const float DISTANCE_SCALE_LOG = logf(DISTANCE_SCALE) / logf(DISTANCE_LOG_BASE); - - distanceCoefficients[lowAgentIndex][highAgentIndex] = minCoefficient; - } - - if (!insideSphericalInjector) { - // off-axis attenuation and spatialization of audio is not performed - // if the listener is inside a spherical injector + // calculate the distance coefficient using the distance to this agent + distanceCoefficient = powf(GEOMETRIC_AMPLITUDE_SCALAR, + 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; - bearingRelativeAngleToSource = 0; // find the angle we need for calculation based on the orientation of the triangle if (otherAgentPosition.x > agentPosition.x) { @@ -225,6 +212,8 @@ int main(int argc, const char* argv[]) { } } + printf("AAS: %f, AB: %f\n", absoluteAngleToSource, agentRingBuffer->getBearing()); + bearingRelativeAngleToSource = absoluteAngleToSource - agentRingBuffer->getBearing(); if (bearingRelativeAngleToSource > 180) { @@ -241,19 +230,19 @@ int main(int argc, const char* argv[]) { angleOfDelivery += 360; } - float offAxisCoefficient = MAX_OFF_AXIS_ATTENUATION + - (OFF_AXIS_ATTENUATION_FORMULA_STEP * (fabsf(angleOfDelivery) / 90.0f)); - - attenuationCoefficient = distanceCoefficients[lowAgentIndex][highAgentIndex] - * otherAgentBuffer->getAttenuationRatio() - * offAxisCoefficient; + offAxisCoefficient = MAX_OFF_AXIS_ATTENUATION + + (OFF_AXIS_ATTENUATION_FORMULA_STEP * (fabsf(angleOfDelivery) / 90.0f)); bearingRelativeAngleToSource *= (M_PI / 180); - - float sinRatio = fabsf(sinf(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 diff --git a/injector/src/main.cpp b/injector/src/main.cpp index 18fa1f27df..8d4ec11859 100644 --- a/injector/src/main.cpp +++ b/injector/src/main.cpp @@ -32,7 +32,7 @@ bool loopAudio = true; float sleepIntervalMin = 1.00; float sleepIntervalMax = 2.00; char *sourceAudioFile = NULL; -const char *allowedParameters = ":rb::t::c::a::f::d::s:"; +const char *allowedParameters = ":sb::t::c::a::f::d::r:"; float floatArguments[4] = {0.0f, 0.0f, 0.0f, 0.0f}; unsigned char volume = DEFAULT_INJECTOR_VOLUME; float triggerDistance = 0.0f; From 7ea9bb4b92a5c6394c110b20235bfa27972a810a Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 4 Jun 2013 12:11:59 -0700 Subject: [PATCH 05/16] remove debug line from previous commit --- audio-mixer/src/main.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/audio-mixer/src/main.cpp b/audio-mixer/src/main.cpp index bc75ac5698..cac9a1eace 100644 --- a/audio-mixer/src/main.cpp +++ b/audio-mixer/src/main.cpp @@ -212,8 +212,6 @@ int main(int argc, const char* argv[]) { } } - printf("AAS: %f, AB: %f\n", absoluteAngleToSource, agentRingBuffer->getBearing()); - bearingRelativeAngleToSource = absoluteAngleToSource - agentRingBuffer->getBearing(); if (bearingRelativeAngleToSource > 180) { From 0f70c9c06bbffd2206d5fe1b9b7f2e80c9c379a2 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 4 Jun 2013 12:52:09 -0700 Subject: [PATCH 06/16] send full quaternion orientation instead of just bearing to audio-mixer --- interface/src/Audio.cpp | 29 +++++++++-------------------- 1 file changed, 9 insertions(+), 20 deletions(-) diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index bf100d733b..16ac7fa4f7 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -133,7 +133,10 @@ int audioCallback (const void* inputBuffer, Agent* audioMixer = agentList->soloAgentOfType(AGENT_TYPE_AUDIO_MIXER); if (audioMixer) { - int leadingBytes = 2 + (sizeof(float) * 4); + glm::vec3 headPosition = interfaceAvatar->getHeadJointPosition(); + glm::quat headOrientation = interfaceAvatar->getHead().getOrientation(); + + int leadingBytes = 1 + sizeof(headPosition) + sizeof(headOrientation) + sizeof(unsigned char); // we need the amount of bytes in the buffer + 1 for type // + 12 for 3 floats for position + float for bearing + 1 attenuation byte @@ -143,29 +146,15 @@ int audioCallback (const void* inputBuffer, unsigned char *currentPacketPtr = dataPacket + 1; // memcpy the three float positions - memcpy(currentPacketPtr, &interfaceAvatar->getHeadJointPosition(), sizeof(float) * 3); - currentPacketPtr += (sizeof(float) * 3); + memcpy(currentPacketPtr, &headPosition, sizeof(headPosition)); + currentPacketPtr += (sizeof(headPosition)); // tell the mixer not to add additional attenuation to our source *(currentPacketPtr++) = 255; - // memcpy the corrected render yaw - float correctedYaw = fmodf(-1 * interfaceAvatar->getAbsoluteHeadYaw(), 360); - - if (correctedYaw > 180) { - correctedYaw -= 360; - } else if (correctedYaw < -180) { - correctedYaw += 360; - } - - if (Application::getInstance()->shouldEchoAudio()) { - correctedYaw = correctedYaw > 0 - ? correctedYaw + AGENT_LOOPBACK_MODIFIER - : correctedYaw - AGENT_LOOPBACK_MODIFIER; - } - - memcpy(currentPacketPtr, &correctedYaw, sizeof(float)); - currentPacketPtr += sizeof(float); + // memcpy our orientation + memcpy(currentPacketPtr, &headOrientation, sizeof(headOrientation)); + currentPacketPtr += sizeof(headOrientation); // copy the audio data to the last BUFFER_LENGTH_BYTES bytes of the data packet memcpy(currentPacketPtr, inputLeft, BUFFER_LENGTH_BYTES); From cd79339670d39691a872a69e96e6fdbf152dc92d Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 4 Jun 2013 15:18:05 -0700 Subject: [PATCH 07/16] rework audio-mixer to use orientations sent by clients --- audio-mixer/src/main.cpp | 88 +++++++++---------------- libraries/audio/src/AudioRingBuffer.cpp | 17 ++--- libraries/audio/src/AudioRingBuffer.h | 6 +- 3 files changed, 41 insertions(+), 70 deletions(-) diff --git a/audio-mixer/src/main.cpp b/audio-mixer/src/main.cpp index cac9a1eace..df38876c31 100644 --- a/audio-mixer/src/main.cpp +++ b/audio-mixer/src/main.cpp @@ -18,6 +18,7 @@ #include #include +#include #include #include #include @@ -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); } diff --git a/libraries/audio/src/AudioRingBuffer.cpp b/libraries/audio/src/AudioRingBuffer.cpp index fe93ece47f..6bdb7f9aae 100644 --- a/libraries/audio/src/AudioRingBuffer.cpp +++ b/libraries/audio/src/AudioRingBuffer.cpp @@ -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; } } diff --git a/libraries/audio/src/AudioRingBuffer.h b/libraries/audio/src/AudioRingBuffer.h index 0a2b8ed7db..a280be0a7c 100644 --- a/libraries/audio/src/AudioRingBuffer.h +++ b/libraries/audio/src/AudioRingBuffer.h @@ -12,6 +12,7 @@ #include #include +#include #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; From 7d3d8f8b43929237a5cd73b1cc3142a3adbd5e39 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 4 Jun 2013 15:31:11 -0700 Subject: [PATCH 08/16] rewrite the AudioInjector to send an orientation quaternion instead of bearing --- audio-mixer/src/main.cpp | 2 +- interface/src/Application.cpp | 4 ++-- libraries/audio/src/AudioInjector.cpp | 14 +++++++------- libraries/audio/src/AudioInjector.h | 6 +++--- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/audio-mixer/src/main.cpp b/audio-mixer/src/main.cpp index df38876c31..4c1ffab1f0 100644 --- a/audio-mixer/src/main.cpp +++ b/audio-mixer/src/main.cpp @@ -207,7 +207,7 @@ int main(int argc, const char* argv[]) { glm::normalize(rotatedListenerPosition)); offAxisCoefficient = MAX_OFF_AXIS_ATTENUATION - + (OFF_AXIS_ATTENUATION_FORMULA_STEP * (fabsf(angleOfDelivery) / 90.0f)); + + (OFF_AXIS_ATTENUATION_FORMULA_STEP * (angleOfDelivery / 90.0f)); float sinRatio = fabsf(sinf(glm::radians(bearingRelativeAngleToSource))); numSamplesDelay = PHASE_DELAY_AT_90 * sinRatio; diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 6ef5d0d5bc..3e493b4882 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2353,7 +2353,7 @@ void Application::maybeEditVoxelUnderCursor() { AudioInjector* voxelInjector = AudioInjectionManager::injectorWithCapacity(11025); voxelInjector->setPosition(glm::vec3(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z)); //_myAvatar.getPosition() - voxelInjector->setBearing(-1 * _myAvatar.getAbsoluteHeadYaw()); +// voxelInjector->setBearing(-1 * _myAvatar.getAbsoluteHeadYaw()); voxelInjector->setVolume (16 * pow (_mouseVoxel.s, 2) / .0000001); //255 is max, and also default value /* for (int i = 0; i @@ -2416,7 +2416,7 @@ void Application::deleteVoxelUnderCursor() { sendVoxelEditMessage(PACKET_HEADER_ERASE_VOXEL, _mouseVoxel); AudioInjector* voxelInjector = AudioInjectionManager::injectorWithCapacity(5000); voxelInjector->setPosition(glm::vec3(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z)); - voxelInjector->setBearing(0); //straight down the z axis +// voxelInjector->setBearing(0); //straight down the z axis voxelInjector->setVolume (255); //255 is max, and also default value diff --git a/libraries/audio/src/AudioInjector.cpp b/libraries/audio/src/AudioInjector.cpp index fbb55a84c3..11dec28dfc 100644 --- a/libraries/audio/src/AudioInjector.cpp +++ b/libraries/audio/src/AudioInjector.cpp @@ -18,9 +18,9 @@ const int MAX_INJECTOR_VOLUME = 0xFF; AudioInjector::AudioInjector(const char* filename) : - _position(), + _position(0.0f, 0.0f, 0.0f), + _orientation(0.0f, 0.0f, 0.0f, 0.0f), _radius(0.0f), - _bearing(0), _volume(MAX_INJECTOR_VOLUME), _indexOfNextSlot(0), _isInjectingAudio(false) @@ -48,9 +48,9 @@ AudioInjector::AudioInjector(const char* filename) : AudioInjector::AudioInjector(int maxNumSamples) : _numTotalSamples(maxNumSamples), - _position(), + _position(0.0f, 0.0f, 0.0f), + _orientation(0.0f, 0.0f, 0.0f, 0.0f), _radius(0.0f), - _bearing(0), _volume(MAX_INJECTOR_VOLUME), _indexOfNextSlot(0), _isInjectingAudio(false) @@ -73,7 +73,7 @@ void AudioInjector::injectAudio(UDPSocket* injectorSocket, sockaddr* destination // calculate the number of bytes required for additional data int leadingBytes = sizeof(PACKET_HEADER) + sizeof(INJECT_AUDIO_AT_POINT_COMMAND) + sizeof(_streamIdentifier) - + sizeof(_position) + sizeof(_bearing) + sizeof(_volume); + + sizeof(_position) + sizeof(_orientation) + sizeof(_volume); if (_radius > 0) { // we'll need 4 extra bytes if the cube side length is being sent as well @@ -104,8 +104,8 @@ void AudioInjector::injectAudio(UDPSocket* injectorSocket, sockaddr* destination *currentPacketPtr = _volume; currentPacketPtr++; - memcpy(currentPacketPtr, &_bearing, sizeof(_bearing)); - currentPacketPtr += sizeof(_bearing); + memcpy(currentPacketPtr, &_orientation, sizeof(_orientation)); + currentPacketPtr += sizeof(_orientation); gettimeofday(&startTime, NULL); int nextFrame = 0; diff --git a/libraries/audio/src/AudioInjector.h b/libraries/audio/src/AudioInjector.h index d8b907d368..f0a7d1f3f8 100644 --- a/libraries/audio/src/AudioInjector.h +++ b/libraries/audio/src/AudioInjector.h @@ -36,8 +36,8 @@ public: const glm::vec3& getPosition() const { return _position; } void setPosition(const glm::vec3& position) { _position = position; } - float getBearing() const { return _bearing; } - void setBearing(float bearing) { _bearing = bearing; } + const glm::quat& getOrientation() const { return _orientation; } + void setOperation(const glm::quat& orientation) { _orientation = orientation; } float getRadius() const { return _radius; } void setRadius(float radius) { _radius = radius; } @@ -49,8 +49,8 @@ private: int16_t* _audioSampleArray; int _numTotalSamples; glm::vec3 _position; + glm::quat _orientation; float _radius; - float _bearing; unsigned char _volume; int _indexOfNextSlot; bool _isInjectingAudio; From bfad6c8f6139931d7cde190287277169a3f35d18 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 4 Jun 2013 16:10:20 -0700 Subject: [PATCH 09/16] fix orientation setter in AudioInjector header --- libraries/audio/src/AudioInjector.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/audio/src/AudioInjector.h b/libraries/audio/src/AudioInjector.h index f0a7d1f3f8..42bc1f1a2c 100644 --- a/libraries/audio/src/AudioInjector.h +++ b/libraries/audio/src/AudioInjector.h @@ -37,7 +37,7 @@ public: void setPosition(const glm::vec3& position) { _position = position; } const glm::quat& getOrientation() const { return _orientation; } - void setOperation(const glm::quat& orientation) { _orientation = orientation; } + void setOrientation(const glm::quat& orientation) { _orientation = orientation; } float getRadius() const { return _radius; } void setRadius(float radius) { _radius = radius; } From 4b208e16783bbe079835c7dc54a6d7439e1971e1 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 4 Jun 2013 16:11:11 -0700 Subject: [PATCH 10/16] project source position onto XZ plane of listener --- audio-mixer/src/main.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/audio-mixer/src/main.cpp b/audio-mixer/src/main.cpp index 4c1ffab1f0..3c9d60b50f 100644 --- a/audio-mixer/src/main.cpp +++ b/audio-mixer/src/main.cpp @@ -196,6 +196,11 @@ int main(int argc, const char* argv[]) { // not performed if listener is inside spherical injector // calculate the angle from the source to the listener + + // project the rotated source position vector onto the XZ plane + rotatedSourcePosition.y = 0.0f; + + // produce an oriented angle about the y-axis bearingRelativeAngleToSource = glm::orientedAngle(glm::vec3(0.0f, 0.0f, -1.0f), glm::normalize(rotatedSourcePosition), glm::vec3(0.0f, 1.0f, 0.0f)); @@ -203,6 +208,7 @@ int main(int argc, const char* argv[]) { // 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)); From e07c55ec43ac4484a6937d08d0f1412226d2ea09 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 4 Jun 2013 16:11:35 -0700 Subject: [PATCH 11/16] set injector orientation from bearing passed as command line argument --- injector/src/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/injector/src/main.cpp b/injector/src/main.cpp index 8d4ec11859..d8f0df9b1f 100644 --- a/injector/src/main.cpp +++ b/injector/src/main.cpp @@ -167,7 +167,7 @@ int main(int argc, char* argv[]) { agentList->startSilentAgentRemovalThread(); injector.setPosition(glm::vec3(::floatArguments[0], ::floatArguments[1], ::floatArguments[2])); - injector.setBearing(*(::floatArguments + 3)); + injector.setOrientation(glm::quat(glm::vec3(0.0f, *(::floatArguments + 3), 0.0f))); injector.setVolume(::volume); if (::radius > 0) { From c5d3365f3e9cb4f5a72c20af08dcc625e35f6ac1 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 4 Jun 2013 16:44:01 -0700 Subject: [PATCH 12/16] correct spatialization and off-axis attenuation for a spherical source --- audio-mixer/src/main.cpp | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/audio-mixer/src/main.cpp b/audio-mixer/src/main.cpp index 3c9d60b50f..6b4790f2ad 100644 --- a/audio-mixer/src/main.cpp +++ b/audio-mixer/src/main.cpp @@ -150,8 +150,8 @@ int main(int argc, const char* argv[]) { if (otherAgent != agent) { glm::vec3 listenerPosition = agentRingBuffer->getPosition(); glm::vec3 relativePosition = otherAgentBuffer->getPosition() - agentRingBuffer->getPosition(); - glm::vec3 rotatedSourcePosition = glm::inverse(agentRingBuffer->getOrientation()) - * relativePosition; + glm::quat inverseOrientation = glm::inverse(agentRingBuffer->getOrientation()); + glm::vec3 rotatedSourcePosition = inverseOrientation * relativePosition; float distanceSquareToSource = glm::dot(relativePosition, relativePosition); @@ -171,14 +171,25 @@ int main(int argc, const char* argv[]) { // 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 closestPoint = glm::normalize(relativePosition) * otherAgentBuffer->getRadius(); + glm::vec3 closestPoint = glm::normalize(-relativePosition) * otherAgentBuffer->getRadius(); // for the other calculations the agent position is the closest point on the sphere - rotatedSourcePosition = closestPoint; + rotatedSourcePosition = inverseOrientation * -closestPoint; // ovveride the distance to the agent with the distance to the point on the // boundary of the sphere distanceSquareToSource = glm::distance2(listenerPosition, closestPoint); + + } else { + // 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 * (angleOfDelivery / 90.0f)); } const float DISTANCE_SCALE = 2.5f; @@ -205,15 +216,6 @@ int main(int argc, const char* argv[]) { glm::normalize(rotatedSourcePosition), glm::vec3(0.0f, 1.0f, 0.0f)); - // 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 * (angleOfDelivery / 90.0f)); float sinRatio = fabsf(sinf(glm::radians(bearingRelativeAngleToSource))); numSamplesDelay = PHASE_DELAY_AT_90 * sinRatio; From fa9b897025d4dfbb94d14834693caae9e38a86c7 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 4 Jun 2013 17:00:55 -0700 Subject: [PATCH 13/16] move mixer related constants above related part of mix --- audio-mixer/src/main.cpp | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/audio-mixer/src/main.cpp b/audio-mixer/src/main.cpp index 6b4790f2ad..023f5db371 100644 --- a/audio-mixer/src/main.cpp +++ b/audio-mixer/src/main.cpp @@ -57,12 +57,6 @@ const float BUFFER_SEND_INTERVAL_USECS = (BUFFER_LENGTH_SAMPLES_PER_CHANNEL / SA const long MAX_SAMPLE_VALUE = std::numeric_limits::max(); const long MIN_SAMPLE_VALUE = std::numeric_limits::min(); -const float PHASE_AMPLITUDE_RATIO_AT_90 = 0.5; -const int PHASE_DELAY_AT_90 = 20; - -const float MAX_OFF_AXIS_ATTENUATION = 0.2f; -const float OFF_AXIS_ATTENUATION_FORMULA_STEP = (1 - MAX_OFF_AXIS_ATTENUATION) / 2.0f; - void plateauAdditionOfSamples(int16_t &mixSample, int16_t sampleToAdd) { long sumSample = sampleToAdd + mixSample; @@ -171,14 +165,14 @@ int main(int argc, const char* argv[]) { // 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 closestPoint = glm::normalize(-relativePosition) * otherAgentBuffer->getRadius(); + glm::vec3 closestPoint = glm::normalize(relativePosition) * otherAgentBuffer->getRadius(); // for the other calculations the agent position is the closest point on the sphere - rotatedSourcePosition = inverseOrientation * -closestPoint; + rotatedSourcePosition = inverseOrientation * closestPoint; // ovveride the distance to the agent with the distance to the point on the // boundary of the sphere - distanceSquareToSource = glm::distance2(listenerPosition, closestPoint); + distanceSquareToSource = glm::distance2(listenerPosition, -closestPoint); } else { // calculate the angle delivery @@ -188,6 +182,9 @@ int main(int argc, const char* argv[]) { float angleOfDelivery = glm::angle(glm::vec3(0.0f, 0.0f, 1.0f), glm::normalize(rotatedListenerPosition)); + const float MAX_OFF_AXIS_ATTENUATION = 0.2f; + const float OFF_AXIS_ATTENUATION_FORMULA_STEP = (1 - MAX_OFF_AXIS_ATTENUATION) / 2.0f; + offAxisCoefficient = MAX_OFF_AXIS_ATTENUATION + (OFF_AXIS_ATTENUATION_FORMULA_STEP * (angleOfDelivery / 90.0f)); } @@ -216,6 +213,8 @@ int main(int argc, const char* argv[]) { glm::normalize(rotatedSourcePosition), glm::vec3(0.0f, 1.0f, 0.0f)); + const float PHASE_AMPLITUDE_RATIO_AT_90 = 0.5; + const int PHASE_DELAY_AT_90 = 20; float sinRatio = fabsf(sinf(glm::radians(bearingRelativeAngleToSource))); numSamplesDelay = PHASE_DELAY_AT_90 * sinRatio; From 7f486c351f862c02d050d633c907dcf9c0a8ca6f Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 4 Jun 2013 17:15:58 -0700 Subject: [PATCH 14/16] correct direction of angle of delivery --- audio-mixer/src/main.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/audio-mixer/src/main.cpp b/audio-mixer/src/main.cpp index 023f5db371..43c6b3ac50 100644 --- a/audio-mixer/src/main.cpp +++ b/audio-mixer/src/main.cpp @@ -177,9 +177,9 @@ int main(int argc, const char* argv[]) { } else { // calculate the angle delivery glm::vec3 rotatedListenerPosition = glm::inverse(otherAgentBuffer->getOrientation()) - * relativePosition; + * relativePosition; - float angleOfDelivery = glm::angle(glm::vec3(0.0f, 0.0f, 1.0f), + float angleOfDelivery = glm::angle(glm::vec3(0.0f, 0.0f, -1.0f), glm::normalize(rotatedListenerPosition)); const float MAX_OFF_AXIS_ATTENUATION = 0.2f; From 6bf6d5a28ef919127fd79e54fa471b426c6a7c8b Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 4 Jun 2013 17:29:33 -0700 Subject: [PATCH 15/16] cleanup NULL comparisons in AgentList --- libraries/shared/src/AgentList.cpp | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/libraries/shared/src/AgentList.cpp b/libraries/shared/src/AgentList.cpp index 2b28ac620d..51ef88794b 100644 --- a/libraries/shared/src/AgentList.cpp +++ b/libraries/shared/src/AgentList.cpp @@ -40,7 +40,7 @@ bool pingUnknownAgentThreadStopFlag = false; AgentList* AgentList::_sharedInstance = NULL; AgentList* AgentList::createInstance(char ownerType, unsigned int socketListenPort) { - if (_sharedInstance == NULL) { + if (!_sharedInstance) { _sharedInstance = new AgentList(ownerType, socketListenPort); } else { printLog("AgentList createInstance called with existing instance.\n"); @@ -50,7 +50,7 @@ AgentList* AgentList::createInstance(char ownerType, unsigned int socketListenPo } AgentList* AgentList::getInstance() { - if (_sharedInstance == NULL) { + if (!_sharedInstance) { printLog("AgentList getInstance called before call to createInstance. Returning NULL pointer.\n"); } @@ -150,14 +150,12 @@ int AgentList::updateAgentWithData(sockaddr *senderAddress, unsigned char *packe int AgentList::updateAgentWithData(Agent *agent, unsigned char *packetData, int dataBytes) { agent->setLastHeardMicrostamp(usecTimestampNow()); - if (agent->getActiveSocket() != NULL) { + if (agent->getActiveSocket()) { agent->recordBytesReceived(dataBytes); } - if (agent->getLinkedData() == NULL) { - if (linkedDataCreateCallback != NULL) { - linkedDataCreateCallback(agent); - } + if (!agent->getLinkedData() && linkedDataCreateCallback) { + linkedDataCreateCallback(agent); } return agent->getLinkedData()->parseData(packetData, dataBytes); @@ -165,7 +163,7 @@ int AgentList::updateAgentWithData(Agent *agent, unsigned char *packetData, int Agent* AgentList::agentWithAddress(sockaddr *senderAddress) { for(AgentList::iterator agent = begin(); agent != end(); agent++) { - if (agent->getActiveSocket() != NULL && socketMatch(agent->getActiveSocket(), senderAddress)) { + if (agent->getActiveSocket() && socketMatch(agent->getActiveSocket(), senderAddress)) { return &(*agent); } } @@ -216,7 +214,7 @@ int AgentList::processDomainServerList(unsigned char *packetData, size_t dataByt Agent* AgentList::addOrUpdateAgent(sockaddr* publicSocket, sockaddr* localSocket, char agentType, uint16_t agentId) { AgentList::iterator agent = end(); - if (publicSocket != NULL) { + if (publicSocket) { for (agent = begin(); agent != end(); agent++) { if (agent->matches(publicSocket, localSocket, agentType)) { // we already have this agent, stop checking @@ -327,8 +325,7 @@ void *pingUnknownAgents(void *args) { for(AgentList::iterator agent = agentList->begin(); agent != agentList->end(); agent++) { - if (agent->getActiveSocket() == NULL - && (agent->getPublicSocket() != NULL && agent->getLocalSocket() != NULL)) { + if (!agent->getActiveSocket() && agent->getPublicSocket() && agent->getLocalSocket()) { // ping both of the sockets for the agent so we can figure out // which socket we can use agentList->getAgentSocket()->send(agent->getPublicSocket(), &PACKET_HEADER_PING, 1); From 351828e8e53ef3bd1bc1f71bc64577942cf91885 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 5 Jun 2013 09:35:43 -0700 Subject: [PATCH 16/16] some magic number removal in injector main --- injector/src/main.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/injector/src/main.cpp b/injector/src/main.cpp index d8f0df9b1f..41e2bc0bbd 100644 --- a/injector/src/main.cpp +++ b/injector/src/main.cpp @@ -27,6 +27,13 @@ const int AVATAR_MIXER_DATA_SEND_INTERVAL_MSECS = 15; const int DEFAULT_INJECTOR_VOLUME = 0xFF; +enum { + INJECTOR_POSITION_X, + INJECTOR_POSITION_Y, + INJECTOR_POSITION_Z, + INJECTOR_YAW +}; + // Command line parameter defaults bool loopAudio = true; float sleepIntervalMin = 1.00; @@ -166,8 +173,10 @@ int main(int argc, char* argv[]) { // start the agent list thread that will kill off agents when they stop talking agentList->startSilentAgentRemovalThread(); - injector.setPosition(glm::vec3(::floatArguments[0], ::floatArguments[1], ::floatArguments[2])); - injector.setOrientation(glm::quat(glm::vec3(0.0f, *(::floatArguments + 3), 0.0f))); + injector.setPosition(glm::vec3(::floatArguments[INJECTOR_POSITION_X], + ::floatArguments[INJECTOR_POSITION_Y], + ::floatArguments[INJECTOR_POSITION_Z])); + injector.setOrientation(glm::quat(glm::vec3(0.0f, ::floatArguments[INJECTOR_YAW], 0.0f))); injector.setVolume(::volume); if (::radius > 0) {