fix the filter with delay and add per listener source pair data

This commit is contained in:
ZappoMan 2014-09-18 14:58:44 -07:00
parent a5ea0479c1
commit 864c1c88a7
4 changed files with 57 additions and 10 deletions

View file

@ -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<QUuid, PositionalAudioStream*>::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);
}
}
}

View file

@ -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);

View file

@ -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];
}

View file

@ -13,10 +13,26 @@
#define hifi_AudioMixerClientData_h
#include <AABox.h>
#include <AudioFormat.h> // For AudioFilterHSF1s and _penumbraFilter
#include <AudioBuffer.h> // For AudioFilterHSF1s and _penumbraFilter
#include <AudioFilter.h> // For AudioFilterHSF1s and _penumbraFilter
#include <AudioFilterBank.h> // 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<QUuid, PositionalAudioStream*> _audioStreams; // mic stream stored under key of null UUID
// TODO: how can we prune this hash when a stream is no longer present?
QHash<QUuid, PerListenerSourcePairData*> _listenerSourcePairData;
quint16 _outgoingMixedAudioSequenceNumber;
AudioStreamStats _downstreamAudioStreamStats;