UE-17938 Fixing some issues that cause mac to sound different than PC client

- Switching to a EQ filter type that is more similar to XAudio2's filter
- Piping the per-voice high-frequency attenuation parameter to a new per-voice low-pass filter
- making the effect processing serial rather than parallel
- Clamping max volumes to 1.0 (linear) before setting volumes on API calls. Not doing this causes sounds to distort as max volume being used was 4.0 and we have volume scale factors greater than 1.0

[CL 2631483 by Aaron McLeran in Main branch]
This commit is contained in:
Aaron McLeran
2015-07-23 18:01:47 -04:00
committed by Aaron.McLeran@epicgames.com
parent a94a6f92c7
commit 64e7ff6ccb
5 changed files with 297 additions and 377 deletions

View File

@@ -50,6 +50,11 @@ bool FCoreAudioDevice::InitializeHardware()
InverseTransform = FMatrix::Identity;
for (int32 Index = 0; Index < CORE_AUDIO_MAX_CHANNELS + 1; ++Index)
{
AudioChannels[Index] = nullptr;
}
for( SInt32 Index = 0; Index < CORE_AUDIO_MAX_CHANNELS; ++Index )
{
Mixer3DInputStatus[ Index ] = false;
@@ -224,6 +229,9 @@ bool FCoreAudioDevice::InitializeHardware()
Status = AUGraphConnectNodeInput( AudioUnitGraph, Mixer3DNode, 0, OutputNode, 0 );
}
// Set the sample rate
SampleRate = Mixer3DFormat.mSampleRate;
if( Status != noErr )
{
UE_LOG(LogInit, Log, TEXT( "Failed to start audio graph!" ) );

View File

@@ -13,8 +13,6 @@
#include "CoreAudioEffects.h"
#include "Engine.h"
extern FCoreAudioSoundSource *GAudioChannels[CORE_AUDIO_MAX_CHANNELS + 1];
static CFBundleRef LoadRadioEffectComponent()
{
bool bLoaded = false;
@@ -89,7 +87,7 @@ TConsoleVariableData<float>* FCoreAudioEffectsManager::Radio_ChebyshevMultiplier
FCoreAudioEffectsManager::FCoreAudioEffectsManager( FAudioDevice* InDevice )
: FAudioEffectsManager( InDevice )
{
#if RADIO_ENABLED
#if CORE_AUDIO_RADIO_ENABLED
RadioBundle = LoadRadioEffectComponent();
bRadioAvailable = (RadioBundle != NULL);
#endif
@@ -97,7 +95,7 @@ FCoreAudioEffectsManager::FCoreAudioEffectsManager( FAudioDevice* InDevice )
FCoreAudioEffectsManager::~FCoreAudioEffectsManager()
{
#if RADIO_ENABLED
#if CORE_AUDIO_RADIO_ENABLED
if(RadioBundle)
{
CFRelease(RadioBundle);
@@ -111,6 +109,7 @@ FCoreAudioEffectsManager::~FCoreAudioEffectsManager()
*/
void FCoreAudioEffectsManager::SetReverbEffectParameters( const FAudioReverbEffect& ReverbEffectParameters )
{
#if CORE_AUDIO_REVERB_ENABLED
float DryWetMix = FMath::Sin(ReverbEffectParameters.Volume*M_PI_2) * 100.0f; // 0.0-100.0, 100.0
float SmallLargeMix = ReverbEffectParameters.GainHF * 100.0f; // 0.0-100.0, 50.0
float PreDelay = ReverbEffectParameters.ReflectionsDelay; // 0.001->0.03, 0.025
@@ -134,7 +133,7 @@ void FCoreAudioEffectsManager::SetReverbEffectParameters( const FAudioReverbEffe
for( uint32 Index = 1; Index < CORE_AUDIO_MAX_CHANNELS + 1; Index++ )
{
FCoreAudioSoundSource *Source = GAudioChannels[Index];
FCoreAudioSoundSource *Source = ((FCoreAudioDevice*)AudioDevice)->AudioChannels[Index];
if( Source && Source->ReverbUnit )
{
AudioUnitSetParameter(Source->ReverbUnit, kReverbParam_DryWetMix, kAudioUnitScope_Global, 0, DryWetMix, 0);
@@ -157,39 +156,51 @@ void FCoreAudioEffectsManager::SetReverbEffectParameters( const FAudioReverbEffe
AudioUnitSetParameter(Source->ReverbUnit, kReverbParam_LargeBrightness, kAudioUnitScope_Global, 0, LargeBrightness, 0);
}
}
#endif
}
/**
* Calls the platform specific code to set the parameters that define EQ
*/
void FCoreAudioEffectsManager::SetEQEffectParameters( const FAudioEQEffect& EQEffectParameters )
void FCoreAudioEffectsManager::SetEQEffectParameters( const FAudioEQEffect& Params )
{
float LowGain = VolumeToDeciBels(EQEffectParameters.LFGain);
float CenterGain = VolumeToDeciBels(EQEffectParameters.MFGain);
float HighGain = VolumeToDeciBels(EQEffectParameters.HFGain);
float LowGain = VolumeToDeciBels(Params.LFGain);
float CenterGain = VolumeToDeciBels(Params.MFGain);
float HighGain = VolumeToDeciBels(Params.HFGain);
for( uint32 Index = 1; Index < CORE_AUDIO_MAX_CHANNELS + 1; Index++ )
{
FCoreAudioSoundSource *Source = GAudioChannels[Index];
if( Source && Source->EQUnit )
FCoreAudioSoundSource *Source = ((FCoreAudioDevice*)AudioDevice)->AudioChannels[Index];
if (Source)
{
AudioUnitSetParameter( Source->EQUnit, kMultibandFilter_LowFrequency, kAudioUnitScope_Global, 0, EQEffectParameters.LFFrequency, 0 );
AudioUnitSetParameter( Source->EQUnit, kMultibandFilter_LowGain, kAudioUnitScope_Global, 0, LowGain, 0 );
if (Source->EQUnit)
{
AudioUnitSetParameter(Source->EQUnit, kAUNBandEQParam_Frequency + 0, kAudioUnitScope_Global, 0, Params.LFFrequency, 0);
AudioUnitSetParameter(Source->EQUnit, kAUNBandEQParam_Gain + 0, kAudioUnitScope_Global, 0, LowGain, 0);
AudioUnitSetParameter(Source->EQUnit, kAUNBandEQParam_Bandwidth + 0, kAudioUnitScope_Global, 0, 1.0f, 0); // from FXEQ_DEFAULT_BANDWIDTH
AudioUnitSetParameter( Source->EQUnit, kMultibandFilter_CenterFreq1, kAudioUnitScope_Global, 0, (EQEffectParameters.MFCutoffFrequency - EQEffectParameters.LFFrequency) / 2.0f, 0 );
AudioUnitSetParameter( Source->EQUnit, kMultibandFilter_CenterGain1, kAudioUnitScope_Global, 0, CenterGain, 0 );
AudioUnitSetParameter( Source->EQUnit, kMultibandFilter_Bandwidth1, kAudioUnitScope_Global, 0, EQEffectParameters.MFBandwidth, 0 );
AudioUnitSetParameter( Source->EQUnit, kMultibandFilter_CenterFreq2, kAudioUnitScope_Global, 0, EQEffectParameters.MFCutoffFrequency, 0 );
AudioUnitSetParameter( Source->EQUnit, kMultibandFilter_CenterGain2, kAudioUnitScope_Global, 0, CenterGain, 0 );
AudioUnitSetParameter( Source->EQUnit, kMultibandFilter_Bandwidth2, kAudioUnitScope_Global, 0, EQEffectParameters.MFBandwidth, 0 );
AudioUnitSetParameter(Source->EQUnit, kAUNBandEQParam_Frequency + 1, kAudioUnitScope_Global, 0, Params.MFCutoffFrequency, 0);
AudioUnitSetParameter(Source->EQUnit, kAUNBandEQParam_Gain + 1, kAudioUnitScope_Global, 0, CenterGain, 0);
AudioUnitSetParameter(Source->EQUnit, kAUNBandEQParam_Bandwidth + 1, kAudioUnitScope_Global, 0, Params.MFBandwidth, 0);
AudioUnitSetParameter( Source->EQUnit, kMultibandFilter_CenterFreq3, kAudioUnitScope_Global, 0, (EQEffectParameters.HFFrequency - EQEffectParameters.MFCutoffFrequency) / 2.0f, 0 );
AudioUnitSetParameter( Source->EQUnit, kMultibandFilter_CenterGain3, kAudioUnitScope_Global, 0, CenterGain, 0 );
AudioUnitSetParameter( Source->EQUnit, kMultibandFilter_Bandwidth3, kAudioUnitScope_Global, 0, EQEffectParameters.MFBandwidth, 0 );
AudioUnitSetParameter(Source->EQUnit, kAUNBandEQParam_Frequency + 2, kAudioUnitScope_Global, 0, Params.HFFrequency, 0);
AudioUnitSetParameter(Source->EQUnit, kAUNBandEQParam_Gain + 2, kAudioUnitScope_Global, 0, HighGain, 0);
AudioUnitSetParameter(Source->EQUnit, kAUNBandEQParam_Bandwidth + 2, kAudioUnitScope_Global, 0, 1.0f, 0); // from FXEQ_DEFAULT_BANDWIDTH
AudioUnitSetParameter( Source->EQUnit, kMultibandFilter_HighFrequency, kAudioUnitScope_Global, 0, EQEffectParameters.HFFrequency, 0 );
AudioUnitSetParameter( Source->EQUnit, kMultibandFilter_HighGain, kAudioUnitScope_Global, 0, HighGain, 0 );
AudioUnitSetParameter(Source->EQUnit, kAUNBandEQParam_Frequency + 3, kAudioUnitScope_Global, 0, 10000.0f, 0); // from FXEQ_DEFAULT_CENTER_3
AudioUnitSetParameter(Source->EQUnit, kAUNBandEQParam_Gain + 3, kAudioUnitScope_Global, 0, 1.0, 0); // from FXEQ_DEFAULT_GAIN
AudioUnitSetParameter(Source->EQUnit, kAUNBandEQParam_Bandwidth + 3, kAudioUnitScope_Global, 0, 1.0f, 0); // from FXEQ_DEFAULT_BANDWIDTH
}
if (Source->LowPassUnit && Source->HighFrequencyGain < 1.0f - KINDA_SMALL_NUMBER)
{
float RadianFrequency = 2.0f * FMath::Sin( PI * 6000.0f * Source->HighFrequencyGain / 48000.0f );
float CuttoffFrequency = RadianFrequency * ((FCoreAudioDevice*)AudioDevice)->SampleRate;
float OneOverQ = ((FCoreAudioDevice*)AudioDevice)->GetLowPassFilterResonance();
AudioUnitSetParameter(Source->LowPassUnit, kLowPassParam_CutoffFrequency, kAudioUnitScope_Global, 0, CuttoffFrequency, 0);
AudioUnitSetParameter(Source->LowPassUnit, kLowPassParam_Resonance, kAudioUnitScope_Global, 0, OneOverQ, 0);
}
}
}
}
@@ -216,7 +227,7 @@ void FCoreAudioEffectsManager::SetRadioEffectParameters( const FAudioRadioEffect
for( uint32 Index = 1; Index < CORE_AUDIO_MAX_CHANNELS + 1; Index++ )
{
FCoreAudioSoundSource *Source = GAudioChannels[Index];
FCoreAudioSoundSource *Source = ((FCoreAudioDevice*)AudioDevice)->AudioChannels[Index];
if( Source && Source->RadioUnit )
{
AudioUnitSetParameter( Source->RadioUnit, RadioParam_ChebyshevPowerMultiplier, kAudioUnitScope_Global, 0, ChebyshevPowerMultiplier, 0 );

View File

@@ -172,7 +172,6 @@ public:
typedef FAsyncTask<class FAsyncRealtimeAudioTaskWorker<FCoreAudioSoundBuffer>> FAsyncRealtimeAudioTask;
/**
* CoreAudio implementation of FSoundSource, the interface used to play, stop and update sources
*/
@@ -294,12 +293,12 @@ protected:
AUNode SourceNode;
AudioUnit SourceUnit;
AUNode StreamSplitterNode;
AudioUnit StreamSplitterUnit;
AUNode EQNode;
AudioUnit EQUnit;
AUNode LowPassNode;
AudioUnit LowPassUnit;
AUNode RadioNode;
AudioUnit RadioUnit;
bool bRadioMuted;
@@ -310,9 +309,6 @@ protected:
bool bDryMuted;
AUNode StreamMergerNode;
AudioUnit StreamMergerUnit;
int32 AudioChannel;
int32 BufferInUse;
int32 NumActiveBuffers;
@@ -323,6 +319,12 @@ private:
void FreeResources();
void InitSourceUnit(AudioStreamBasicDescription* Format, AUNode& HeadNode);
void InitLowPassEffect(AudioStreamBasicDescription* Format, AUNode& HeadNode);
void InitRadioSourceEffect(AudioStreamBasicDescription* Format, AUNode& HeadNode);
void InitEqSourceEffect(AudioStreamBasicDescription* Format, AUNode& HeadNode);
void InitReverbSourceEffect(AudioStreamBasicDescription* Format, AUNode& HeadNode);
friend class FCoreAudioDevice;
friend class FCoreAudioEffectsManager;
};
@@ -391,6 +393,19 @@ class FCoreAudioDevice : public FAudioDevice
return ( ( InputNum << 16 ) | ( OutputNum & 0x0000FFFF ) );
}
int32 FindFreeAudioChannel()
{
for (int32 Index = 1; Index < CORE_AUDIO_MAX_CHANNELS + 1; Index++)
{
if (AudioChannels[Index] == nullptr)
{
return Index;
}
}
return 0;
}
protected:
/** Inverse listener transformation, used for spatialization */
@@ -409,11 +424,14 @@ private:
AudioStreamBasicDescription MatrixMixerInputFormat;
AudioStreamBasicDescription MatrixMixerOutputFormat;
bool Mixer3DInputStatus[CORE_AUDIO_MAX_MULTICHANNEL_AUDIOCHANNELS];
bool MatrixMixerInputStatus[CORE_AUDIO_MAX_CHANNELS];
bool Mixer3DInputStatus[CORE_AUDIO_MAX_CHANNELS];
bool MatrixMixerInputStatus[CORE_AUDIO_MAX_MULTICHANNEL_AUDIOCHANNELS];
class FCoreAudioSoundSource* AudioChannels[CORE_AUDIO_MAX_CHANNELS + 1];
friend class FCoreAudioSoundBuffer;
friend class FCoreAudioSoundSource;
friend class FCoreAudioEffectsManager;
};
#endif

View File

@@ -7,9 +7,10 @@
#ifndef _INC_COREAUDIOEFFECTS
#define _INC_COREAUDIOEFFECTS
#define REVERB_ENABLED 1
#define EQ_ENABLED 1
#define RADIO_ENABLED 1
#define CORE_AUDIO_LOWPASS_ENABLED 1
#define CORE_AUDIO_REVERB_ENABLED 1
#define CORE_AUDIO_EQ_ENABLED 1
#define CORE_AUDIO_RADIO_ENABLED 1
/**
* CoreAudio effects manager