From 864c1c88a703c4552cf31bb61a098615172ff5dd Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 18 Sep 2014 14:58:44 -0700 Subject: [PATCH] fix the filter with delay and add per listener source pair data --- assignment-client/src/audio/AudioMixer.cpp | 26 +++++++++++++------ assignment-client/src/audio/AudioMixer.h | 7 +++-- .../src/audio/AudioMixerClientData.cpp | 14 ++++++++++ .../src/audio/AudioMixerClientData.h | 20 ++++++++++++++ 4 files changed, 57 insertions(+), 10 deletions(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index 9d56e02a67..7f1825084b 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -96,7 +96,6 @@ AudioMixer::AudioMixer(const QByteArray& packet) : { // constant defined in AudioMixer.h. However, we don't want to include this here // we will soon find a better common home for these audio-related constants - _penumbraFilter.initialize(SAMPLE_RATE, (NETWORK_BUFFER_LENGTH_SAMPLES_STEREO + (SAMPLE_PHASE_DELAY_AT_90 * 2)) / 2); } AudioMixer::~AudioMixer() { @@ -108,8 +107,10 @@ const float ATTENUATION_BEGINS_AT_DISTANCE = 1.0f; const float ATTENUATION_AMOUNT_PER_DOUBLING_IN_DISTANCE = 0.18f; const float RADIUS_OF_HEAD = 0.076f; -int AudioMixer::addStreamToMixForListeningNodeWithStream(PositionalAudioStream* streamToAdd, - AvatarAudioStream* listeningNodeStream) { +int AudioMixer::addStreamToMixForListeningNodeWithStream(AudioMixerClientData* listenerNodeData, + const QUuid& streamUUID, + PositionalAudioStream* streamToAdd, + AvatarAudioStream* listeningNodeStream) { // If repetition with fade is enabled: // If streamToAdd could not provide a frame (it was starved), then we'll mix its previously-mixed frame // This is preferable to not mixing it at all since that's equivalent to inserting silence. @@ -413,11 +414,13 @@ int AudioMixer::addStreamToMixForListeningNodeWithStream(PositionalAudioStream* << -bearingRelativeAngleToSource; #endif + // Get our per listener/source data so we can get our filter + AudioFilterHSF1s& penumbraFilter = listenerNodeData->getListenerSourcePairData(streamUUID)->getPenumbraFilter(); + // set the gain on both filter channels - _penumbraFilter.reset(); - _penumbraFilter.setParameters(0, 0, SAMPLE_RATE, penumbraFilterFrequency, penumbraFilterGainL, penumbraFilterSlope); - _penumbraFilter.setParameters(0, 1, SAMPLE_RATE, penumbraFilterFrequency, penumbraFilterGainR, penumbraFilterSlope); - _penumbraFilter.render(_preMixSamples, _preMixSamples, NETWORK_BUFFER_LENGTH_SAMPLES_STEREO / 2); + penumbraFilter.setParameters(0, 0, SAMPLE_RATE, penumbraFilterFrequency, penumbraFilterGainL, penumbraFilterSlope); + penumbraFilter.setParameters(0, 1, SAMPLE_RATE, penumbraFilterFrequency, penumbraFilterGainR, penumbraFilterSlope); + penumbraFilter.render(_preMixSamples, _preMixSamples, NETWORK_BUFFER_LENGTH_SAMPLES_STEREO / 2); } // Actually mix the _preMixSamples into the _mixSamples here. @@ -430,6 +433,7 @@ int AudioMixer::addStreamToMixForListeningNodeWithStream(PositionalAudioStream* int AudioMixer::prepareMixForListeningNode(Node* node) { AvatarAudioStream* nodeAudioStream = ((AudioMixerClientData*) node->getLinkedData())->getAvatarAudioStream(); + AudioMixerClientData* listenerNodeData = (AudioMixerClientData*)node->getLinkedData(); // zero out the client mix for this node memset(_preMixSamples, 0, sizeof(_preMixSamples)); @@ -447,9 +451,15 @@ int AudioMixer::prepareMixForListeningNode(Node* node) { QHash::ConstIterator i; for (i = otherNodeAudioStreams.constBegin(); i != otherNodeAudioStreams.constEnd(); i++) { PositionalAudioStream* otherNodeStream = i.value(); + QUuid streamUUID = i.key(); + if (otherNodeStream->getType() == PositionalAudioStream::Microphone) { + streamUUID = otherNode->getUUID(); + } + if (*otherNode != *node || otherNodeStream->shouldLoopbackForNode()) { - streamsMixed += addStreamToMixForListeningNodeWithStream(otherNodeStream, nodeAudioStream); + streamsMixed += addStreamToMixForListeningNodeWithStream(listenerNodeData, streamUUID, + otherNodeStream, nodeAudioStream); } } } diff --git a/assignment-client/src/audio/AudioMixer.h b/assignment-client/src/audio/AudioMixer.h index afc59d3641..1594dbda9a 100644 --- a/assignment-client/src/audio/AudioMixer.h +++ b/assignment-client/src/audio/AudioMixer.h @@ -22,6 +22,7 @@ class PositionalAudioStream; class AvatarAudioStream; +class AudioMixerClientData; const int SAMPLE_PHASE_DELAY_AT_90 = 20; @@ -46,8 +47,10 @@ public slots: private: /// adds one stream to the mix for a listening node - int addStreamToMixForListeningNodeWithStream(PositionalAudioStream* streamToAdd, - AvatarAudioStream* listeningNodeStream); + int addStreamToMixForListeningNodeWithStream(AudioMixerClientData* listenerNodeData, + const QUuid& streamUUID, + PositionalAudioStream* streamToAdd, + AvatarAudioStream* listeningNodeStream); /// prepares and sends a mix to one Node int prepareMixForListeningNode(Node* node); diff --git a/assignment-client/src/audio/AudioMixerClientData.cpp b/assignment-client/src/audio/AudioMixerClientData.cpp index 68ab7d74e1..6c326b3d28 100644 --- a/assignment-client/src/audio/AudioMixerClientData.cpp +++ b/assignment-client/src/audio/AudioMixerClientData.cpp @@ -33,6 +33,11 @@ AudioMixerClientData::~AudioMixerClientData() { // delete this attached InboundAudioStream delete i.value(); } + + // clean up our pair data... + foreach(PerListenerSourcePairData* pairData, _listenerSourcePairData) { + delete pairData; + } } AvatarAudioStream* AudioMixerClientData::getAvatarAudioStream() const { @@ -302,3 +307,12 @@ void AudioMixerClientData::printAudioStreamStats(const AudioStreamStats& streamS formatUsecTime(streamStats._timeGapWindowMax).toLatin1().data(), formatUsecTime(streamStats._timeGapWindowAverage).toLatin1().data()); } + + +PerListenerSourcePairData* AudioMixerClientData::getListenerSourcePairData(const QUuid& sourceUUID) { + if (!_listenerSourcePairData.contains(sourceUUID)) { + PerListenerSourcePairData* newData = new PerListenerSourcePairData(); + _listenerSourcePairData[sourceUUID] = newData; + } + return _listenerSourcePairData[sourceUUID]; +} diff --git a/assignment-client/src/audio/AudioMixerClientData.h b/assignment-client/src/audio/AudioMixerClientData.h index 0ce4ecc36a..65a65f3d77 100644 --- a/assignment-client/src/audio/AudioMixerClientData.h +++ b/assignment-client/src/audio/AudioMixerClientData.h @@ -13,10 +13,26 @@ #define hifi_AudioMixerClientData_h #include +#include // For AudioFilterHSF1s and _penumbraFilter +#include // For AudioFilterHSF1s and _penumbraFilter +#include // For AudioFilterHSF1s and _penumbraFilter +#include // For AudioFilterHSF1s and _penumbraFilter #include "PositionalAudioStream.h" #include "AvatarAudioStream.h" +class PerListenerSourcePairData { +public: + PerListenerSourcePairData() { + const int SAMPLE_PHASE_DELAY_AT_90 = 20; + _penumbraFilter.initialize(SAMPLE_RATE, (NETWORK_BUFFER_LENGTH_SAMPLES_STEREO + (SAMPLE_PHASE_DELAY_AT_90 * 2)) / 2); + }; + AudioFilterHSF1s& getPenumbraFilter() { return _penumbraFilter; } + +private: + AudioFilterHSF1s _penumbraFilter; +}; + class AudioMixerClientData : public NodeData { public: AudioMixerClientData(); @@ -40,12 +56,16 @@ public: void printUpstreamDownstreamStats() const; + PerListenerSourcePairData* getListenerSourcePairData(const QUuid& sourceUUID); private: void printAudioStreamStats(const AudioStreamStats& streamStats) const; private: QHash _audioStreams; // mic stream stored under key of null UUID + // TODO: how can we prune this hash when a stream is no longer present? + QHash _listenerSourcePairData; + quint16 _outgoingMixedAudioSequenceNumber; AudioStreamStats _downstreamAudioStreamStats;