mirror of
https://github.com/lubosz/overte.git
synced 2025-08-07 17:41:12 +02:00
move filter to single instance in mixer, and do filtering on pre-mix buffer not the mixed buffer
This commit is contained in:
parent
c30ef9c331
commit
ab447e20ee
4 changed files with 33 additions and 27 deletions
|
@ -57,6 +57,8 @@
|
||||||
#include "AvatarAudioStream.h"
|
#include "AvatarAudioStream.h"
|
||||||
#include "InjectedAudioStream.h"
|
#include "InjectedAudioStream.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#include "AudioMixer.h"
|
#include "AudioMixer.h"
|
||||||
|
|
||||||
const float LOUDNESS_TO_DISTANCE_RATIO = 0.00001f;
|
const float LOUDNESS_TO_DISTANCE_RATIO = 0.00001f;
|
||||||
|
@ -92,7 +94,9 @@ AudioMixer::AudioMixer(const QByteArray& packet) :
|
||||||
_timeSpentPerHashMatchCallStats(0, READ_DATAGRAMS_STATS_WINDOW_SECONDS),
|
_timeSpentPerHashMatchCallStats(0, READ_DATAGRAMS_STATS_WINDOW_SECONDS),
|
||||||
_readPendingCallsPerSecondStats(1, READ_DATAGRAMS_STATS_WINDOW_SECONDS)
|
_readPendingCallsPerSecondStats(1, READ_DATAGRAMS_STATS_WINDOW_SECONDS)
|
||||||
{
|
{
|
||||||
|
// 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() {
|
AudioMixer::~AudioMixer() {
|
||||||
|
@ -257,6 +261,7 @@ int AudioMixer::addStreamToMixForListeningNodeWithStream(PositionalAudioStream*
|
||||||
|
|
||||||
// we need to do several things in this process:
|
// we need to do several things in this process:
|
||||||
// 1) convert from mono to stereo by copying each input sample into the left and right output samples
|
// 1) convert from mono to stereo by copying each input sample into the left and right output samples
|
||||||
|
// 2)
|
||||||
// 2) apply an attenuation AND fade to all samples (left and right)
|
// 2) apply an attenuation AND fade to all samples (left and right)
|
||||||
// 3) based on the bearing relative angle to the source we will weaken and delay either the left or
|
// 3) based on the bearing relative angle to the source we will weaken and delay either the left or
|
||||||
// right channel of the input into the output
|
// right channel of the input into the output
|
||||||
|
@ -314,7 +319,7 @@ int AudioMixer::addStreamToMixForListeningNodeWithStream(PositionalAudioStream*
|
||||||
for (int i = 0; i < numSamplesDelay; i++) {
|
for (int i = 0; i < numSamplesDelay; i++) {
|
||||||
int16_t originalHistoricalSample = *delayStreamSourceSamples;
|
int16_t originalHistoricalSample = *delayStreamSourceSamples;
|
||||||
|
|
||||||
_clientSamples[delayedChannelHistoricalAudioOutputIndex] += originalHistoricalSample
|
_preMixSamples[delayedChannelHistoricalAudioOutputIndex] += originalHistoricalSample
|
||||||
* attenuationAndWeakChannelRatioAndFade;
|
* attenuationAndWeakChannelRatioAndFade;
|
||||||
++delayStreamSourceSamples; // move our input pointer
|
++delayStreamSourceSamples; // move our input pointer
|
||||||
delayedChannelHistoricalAudioOutputIndex += OUTPUT_SAMPLES_PER_INPUT_SAMPLE; // move our output sample
|
delayedChannelHistoricalAudioOutputIndex += OUTPUT_SAMPLES_PER_INPUT_SAMPLE; // move our output sample
|
||||||
|
@ -329,10 +334,10 @@ int AudioMixer::addStreamToMixForListeningNodeWithStream(PositionalAudioStream*
|
||||||
|
|
||||||
// since we might be delayed, don't write beyond our maxOutputIndex
|
// since we might be delayed, don't write beyond our maxOutputIndex
|
||||||
if (leftDestinationIndex <= maxOutputIndex) {
|
if (leftDestinationIndex <= maxOutputIndex) {
|
||||||
_clientSamples[leftDestinationIndex] += leftSideSample;
|
_preMixSamples[leftDestinationIndex] += leftSideSample;
|
||||||
}
|
}
|
||||||
if (rightDestinationIndex <= maxOutputIndex) {
|
if (rightDestinationIndex <= maxOutputIndex) {
|
||||||
_clientSamples[rightDestinationIndex] += rightSideSample;
|
_preMixSamples[rightDestinationIndex] += rightSideSample;
|
||||||
}
|
}
|
||||||
|
|
||||||
leftDestinationIndex += OUTPUT_SAMPLES_PER_INPUT_SAMPLE;
|
leftDestinationIndex += OUTPUT_SAMPLES_PER_INPUT_SAMPLE;
|
||||||
|
@ -345,7 +350,7 @@ int AudioMixer::addStreamToMixForListeningNodeWithStream(PositionalAudioStream*
|
||||||
float attenuationAndFade = attenuationCoefficient * repeatedFrameFadeFactor;
|
float attenuationAndFade = attenuationCoefficient * repeatedFrameFadeFactor;
|
||||||
|
|
||||||
for (int s = 0; s < NETWORK_BUFFER_LENGTH_SAMPLES_STEREO; s++) {
|
for (int s = 0; s < NETWORK_BUFFER_LENGTH_SAMPLES_STEREO; s++) {
|
||||||
_clientSamples[s] = glm::clamp(_clientSamples[s] + (int)(streamPopOutput[s / stereoDivider] * attenuationAndFade),
|
_preMixSamples[s] = glm::clamp(_preMixSamples[s] + (int)(streamPopOutput[s / stereoDivider] * attenuationAndFade),
|
||||||
MIN_SAMPLE_VALUE, MAX_SAMPLE_VALUE);
|
MIN_SAMPLE_VALUE, MAX_SAMPLE_VALUE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -409,12 +414,15 @@ int AudioMixer::addStreamToMixForListeningNodeWithStream(PositionalAudioStream*
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// set the gain on both filter channels
|
// set the gain on both filter channels
|
||||||
AudioFilterHSF1s& penumbraFilter = streamToAdd->getFilter();
|
_penumbraFilter.reset();
|
||||||
|
_penumbraFilter.setParameters(0, 0, SAMPLE_RATE, penumbraFilterFrequency, penumbraFilterGainL, penumbraFilterSlope);
|
||||||
penumbraFilter.setParameters(0, 0, SAMPLE_RATE, penumbraFilterFrequency, penumbraFilterGainL, penumbraFilterSlope);
|
_penumbraFilter.setParameters(0, 1, SAMPLE_RATE, penumbraFilterFrequency, penumbraFilterGainR, penumbraFilterSlope);
|
||||||
penumbraFilter.setParameters(0, 1, SAMPLE_RATE, penumbraFilterFrequency, penumbraFilterGainR, penumbraFilterSlope);
|
_penumbraFilter.render(_preMixSamples, _preMixSamples, NETWORK_BUFFER_LENGTH_SAMPLES_STEREO / 2);
|
||||||
|
}
|
||||||
penumbraFilter.render(_clientSamples, _clientSamples, NETWORK_BUFFER_LENGTH_SAMPLES_STEREO / 2);
|
|
||||||
|
// Actually mix the _preMixSamples into the _mixSamples here.
|
||||||
|
for (int s = 0; s < NETWORK_BUFFER_LENGTH_SAMPLES_STEREO; s++) {
|
||||||
|
_mixSamples[s] = glm::clamp(_mixSamples[s] + _preMixSamples[s], MIN_SAMPLE_VALUE, MAX_SAMPLE_VALUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -424,7 +432,8 @@ int AudioMixer::prepareMixForListeningNode(Node* node) {
|
||||||
AvatarAudioStream* nodeAudioStream = ((AudioMixerClientData*) node->getLinkedData())->getAvatarAudioStream();
|
AvatarAudioStream* nodeAudioStream = ((AudioMixerClientData*) node->getLinkedData())->getAvatarAudioStream();
|
||||||
|
|
||||||
// zero out the client mix for this node
|
// zero out the client mix for this node
|
||||||
memset(_clientSamples, 0, NETWORK_BUFFER_LENGTH_BYTES_STEREO);
|
memset(_preMixSamples, 0, sizeof(_preMixSamples));
|
||||||
|
memset(_mixSamples, 0, sizeof(_mixSamples));
|
||||||
|
|
||||||
// loop through all other nodes that have sufficient audio to mix
|
// loop through all other nodes that have sufficient audio to mix
|
||||||
int streamsMixed = 0;
|
int streamsMixed = 0;
|
||||||
|
@ -817,7 +826,7 @@ void AudioMixer::run() {
|
||||||
dataAt += sizeof(quint16);
|
dataAt += sizeof(quint16);
|
||||||
|
|
||||||
// pack mixed audio samples
|
// pack mixed audio samples
|
||||||
memcpy(dataAt, _clientSamples, NETWORK_BUFFER_LENGTH_BYTES_STEREO);
|
memcpy(dataAt, _mixSamples, NETWORK_BUFFER_LENGTH_BYTES_STEREO);
|
||||||
dataAt += NETWORK_BUFFER_LENGTH_BYTES_STEREO;
|
dataAt += NETWORK_BUFFER_LENGTH_BYTES_STEREO;
|
||||||
} else {
|
} else {
|
||||||
// pack header
|
// pack header
|
||||||
|
|
|
@ -13,6 +13,10 @@
|
||||||
#define hifi_AudioMixer_h
|
#define hifi_AudioMixer_h
|
||||||
|
|
||||||
#include <AABox.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 <AudioRingBuffer.h>
|
#include <AudioRingBuffer.h>
|
||||||
#include <ThreadedAssignment.h>
|
#include <ThreadedAssignment.h>
|
||||||
|
|
||||||
|
@ -23,7 +27,6 @@ const int SAMPLE_PHASE_DELAY_AT_90 = 20;
|
||||||
|
|
||||||
const int READ_DATAGRAMS_STATS_WINDOW_SECONDS = 30;
|
const int READ_DATAGRAMS_STATS_WINDOW_SECONDS = 30;
|
||||||
|
|
||||||
|
|
||||||
/// Handles assignments of type AudioMixer - mixing streams of audio and re-distributing to various clients.
|
/// Handles assignments of type AudioMixer - mixing streams of audio and re-distributing to various clients.
|
||||||
class AudioMixer : public ThreadedAssignment {
|
class AudioMixer : public ThreadedAssignment {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
@ -48,11 +51,17 @@ private:
|
||||||
|
|
||||||
/// prepares and sends a mix to one Node
|
/// prepares and sends a mix to one Node
|
||||||
int prepareMixForListeningNode(Node* node);
|
int prepareMixForListeningNode(Node* node);
|
||||||
|
|
||||||
|
// used on a per stream basis to run the filter on before mixing, large enough to handle the historical
|
||||||
|
// data from a phase delay as well as an entire network buffer
|
||||||
|
int16_t _preMixSamples[NETWORK_BUFFER_LENGTH_SAMPLES_STEREO + (SAMPLE_PHASE_DELAY_AT_90 * 2)];
|
||||||
|
|
||||||
// client samples capacity is larger than what will be sent to optimize mixing
|
// client samples capacity is larger than what will be sent to optimize mixing
|
||||||
// we are MMX adding 4 samples at a time so we need client samples to have an extra 4
|
// we are MMX adding 4 samples at a time so we need client samples to have an extra 4
|
||||||
int16_t _clientSamples[NETWORK_BUFFER_LENGTH_SAMPLES_STEREO + (SAMPLE_PHASE_DELAY_AT_90 * 2)];
|
int16_t _mixSamples[NETWORK_BUFFER_LENGTH_SAMPLES_STEREO + (SAMPLE_PHASE_DELAY_AT_90 * 2)];
|
||||||
|
|
||||||
|
AudioFilterHSF1s _penumbraFilter;
|
||||||
|
|
||||||
void perSecondActions();
|
void perSecondActions();
|
||||||
|
|
||||||
QString getReadPendingDatagramsCallsPerSecondsStatsString() const;
|
QString getReadPendingDatagramsCallsPerSecondsStatsString() const;
|
||||||
|
|
|
@ -33,10 +33,6 @@ PositionalAudioStream::PositionalAudioStream(PositionalAudioStream::Type type, b
|
||||||
_lastPopOutputLoudness(0.0f),
|
_lastPopOutputLoudness(0.0f),
|
||||||
_listenerUnattenuatedZone(NULL)
|
_listenerUnattenuatedZone(NULL)
|
||||||
{
|
{
|
||||||
// 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
|
|
||||||
const int SAMPLE_PHASE_DELAY_AT_90 = 20;
|
|
||||||
_filter.initialize(SAMPLE_RATE, (NETWORK_BUFFER_LENGTH_SAMPLES_STEREO + (SAMPLE_PHASE_DELAY_AT_90 * 2)) / 2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PositionalAudioStream::resetStats() {
|
void PositionalAudioStream::resetStats() {
|
||||||
|
|
|
@ -16,10 +16,6 @@
|
||||||
#include <AABox.h>
|
#include <AABox.h>
|
||||||
|
|
||||||
#include "InboundAudioStream.h"
|
#include "InboundAudioStream.h"
|
||||||
#include "AudioFormat.h"
|
|
||||||
#include "AudioBuffer.h"
|
|
||||||
#include "AudioFilter.h"
|
|
||||||
#include "AudioFilterBank.h"
|
|
||||||
|
|
||||||
const int AUDIOMIXER_INBOUND_RING_BUFFER_FRAME_CAPACITY = 100;
|
const int AUDIOMIXER_INBOUND_RING_BUFFER_FRAME_CAPACITY = 100;
|
||||||
|
|
||||||
|
@ -50,8 +46,6 @@ public:
|
||||||
|
|
||||||
void setListenerUnattenuatedZone(AABox* listenerUnattenuatedZone) { _listenerUnattenuatedZone = listenerUnattenuatedZone; }
|
void setListenerUnattenuatedZone(AABox* listenerUnattenuatedZone) { _listenerUnattenuatedZone = listenerUnattenuatedZone; }
|
||||||
|
|
||||||
AudioFilterHSF1s& getFilter() { return _filter; }
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// disallow copying of PositionalAudioStream objects
|
// disallow copying of PositionalAudioStream objects
|
||||||
PositionalAudioStream(const PositionalAudioStream&);
|
PositionalAudioStream(const PositionalAudioStream&);
|
||||||
|
@ -70,8 +64,6 @@ protected:
|
||||||
float _lastPopOutputTrailingLoudness;
|
float _lastPopOutputTrailingLoudness;
|
||||||
float _lastPopOutputLoudness;
|
float _lastPopOutputLoudness;
|
||||||
AABox* _listenerUnattenuatedZone;
|
AABox* _listenerUnattenuatedZone;
|
||||||
|
|
||||||
AudioFilterHSF1s _filter;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_PositionalAudioStream_h
|
#endif // hifi_PositionalAudioStream_h
|
||||||
|
|
Loading…
Reference in a new issue