;
; uplink_echo.dspg
;

graphName uplink_echo

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; 	Macros
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

[def MIC_INPUT_CHANNEL_COUNT 1]
[def REF_INPUT_CHANNEL_COUNT 2]
[def MIC_CLIP_DATA_INPUT_CHANNEL_COUNT 1]
[def IO_BLOCK_SIZE 240]
[def IO_SAMPLE_RATE 24000]
[def ENABLE_MEDIA_CHAT 0]
[def ENABLE_SPATIAL_CHAT 0]

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; 	Constants
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; ECV5
[def EC_MicEcleeXcorr 37]
[def EC_SxxTimeAligned 34]
[def EC_IRDelay 8]
[def EC_RelativeDeltaEIR 3]
[def EC_EcleeEnergy 69]

; EchoGate_V3
[def kAUEchoGateV3_EcoEstInputBus 0]
[def kAUEchoGateV3_TimeAlignedRefInputBus 1]
[def kAUEchoGateV3_EsOutInputBus 2]
[def kAUEchoGateV3_EcoEstInputBusFreq 3]
[def kAUEchoGateV3_ResGainInputBus 4]
[def kAUEchoGateV3_NetSuppGainInputBus 5]
[def kAUEchoGateV3Param_CurrDLGain 0]
[def kAUEchoGateV3Param_SpeechProbability 2]
[def kAUEchoGateV3Param_SpeexSpeechProbability 3]
[def kAUEchoGateV3Param_RelativeDeltaEIR 4]
[def kAUEchoGateV3Param_CurrentGateScale 11]
[def kAUEchoGateV3Param_PlayBackScenario 14]
[def kAUEchoGateV3Param_AGCGain 17]
[def kAUEchoGateV3Param_PostGain 18]
[def kAUEchoGateV3Param_IRDelay 19]
[def kAUEchoGateV3Param_NoiseSPLEstimate 37]

; AGCV2
[def kAUAGCV2Param_CurrentGainDb 1]
[def kAUAGCV2Param_ExtNoiseSplEstimate 18]
[def kAUAGCV2Param_PostGainDb 27]
[def kAUAGCV2Param_ExtVadSpeechProbability 35]

;AUNeuralNet
[def kAUNeuralNetLatencySamples 14]
[def kAUNeuralNetSignalProbability 19]

; Misc
[def kAUClipDetectorParameter_ClippingFlag 1]
[def kAUDSPGraphProperty_PropertyStripResourcePath prrp]
[def kAUNeuralNetParam_NeuralNetModelPathBaseOverride 40000]
[def kAudioUnitProperty_BypassEffect 21]

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;	I/O
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

in MicInput
in RefInput
in MicClipDataInput
out MicOutput

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;	Boxes
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
box MicClipDataChannelSelector (aufx clsl) 1 1
box MicPostSRCClipDetector (aufx cldt appl) 1 1
box MicPostSRCClipDetector_DeadEnd dead 1 0
box MicChannelSelector (aufx clsl) 1 1
box MicPreProcessingGain dbgn 1 1

; Mic ECv5
box Mic1LECV5 (aufx lec5) 2 3

; Parallel path alignments around VI DNN
box  VIAlignRefInput  delay 1 1

; VI DNN
box ecleeScaleForVI dbgn 1 1
box VIRESjoin      join 2 1
box VIDNN (aufx nnet appl) 1 2
box VIRESSplit     split 1 2
box VIAlignInputEclee delay 1 1
box VIGainSelector (aufx clsl) 1 1
box VIEcleeFFT fft 1 1

; EQ for speech and noise output streams from VIDNN processing
box SpeechNoiseEQ (aufx tmst) 1 1
box SpeechNoiseEQJoiner join 2 1
box SpeechNoiseEQSplitter split 1 2

; Ambient MixBack related boxes
box NoiseExtractDiff adif 2 1
box AmbGain     dbgn 1 1    ; for scaling ambience
box VoiceAmbMix asum 2 1    ; adding scaled components

; Components after Reverb + DNNs + MDNS
box MixFFT       fft 1 1

; Input alignment and selection for Wide Spectrum
box VIAlignInput delay 1 1
box PathSelector (aufx clsl) 1 1
box PathSelectorJoiner join 2 1
box eclee_present parameter_greater_or_equal 0 0
box eclee_present_prop property_cast 0 0

; Constant ABLs
box UnityGain constant 0 1

; Echo gate (Mixed channel)
box GateV3 (aufx egt3 appl) 6 1
box GateRefFFT fft 1 1
box GateV3OutDeadEnd dead 1 0
box gateGain gain 1 1

; Boxes to override gate gain application when echo is low
box echo_absent parameter_greater_or_equal 0 0
box gateGainOverride parameter_max 0 0

; Post-gate AUs
box VAD (aufx dspg appl) 1 1
box VADDeadEnd dead 1 0
box Mute gain 1 1
box Deesser (aufx dees appl) 1 1
box AGCV2 (aufx agc2 appl) 1 1

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;	Wires
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

; Inputs
wire MicClipDataInput MicClipDataChannelSelector ([IO_SAMPLE_RATE] [MIC_INPUT_CHANNEL_COUNT] [IO_BLOCK_SIZE])
wire MicClipDataChannelSelector MicPostSRCClipDetector ([IO_SAMPLE_RATE] 1 [IO_BLOCK_SIZE])
wire MicPostSRCClipDetector MicPostSRCClipDetector_DeadEnd ([IO_SAMPLE_RATE] 1 [IO_BLOCK_SIZE])
wire MicInput MicChannelSelector ([IO_SAMPLE_RATE] [MIC_INPUT_CHANNEL_COUNT] [IO_BLOCK_SIZE])
wire MicChannelSelector MicPreProcessingGain ([IO_SAMPLE_RATE] 1 [IO_BLOCK_SIZE])

; Mic 1 LEC
wire MicPreProcessingGain (Mic1LECV5 0)   ([IO_SAMPLE_RATE] 1 [IO_BLOCK_SIZE])
wire RefInput (Mic1LECV5 1) ([IO_SAMPLE_RATE] [REF_INPUT_CHANNEL_COUNT] [IO_BLOCK_SIZE])

; ===============================================================================
; VI DNN and Ambience Extract
; ===============================================================================
; Input and outputs to VI-RES DNN
wire (Mic1LECV5 0)      (VIRESjoin 0) ([IO_SAMPLE_RATE] 1 [IO_BLOCK_SIZE])
wire (Mic1LECV5 1) 		ecleeScaleForVI ([IO_SAMPLE_RATE] 1 [IO_BLOCK_SIZE])
wire ecleeScaleForVI 	(VIRESjoin 1) ([IO_SAMPLE_RATE] 1 [IO_BLOCK_SIZE])
wire VIRESjoin    		(VIDNN 0)     ([IO_SAMPLE_RATE] 2 [IO_BLOCK_SIZE])
wire (VIDNN 0)    		VIRESSplit    ([IO_SAMPLE_RATE] 2 [IO_BLOCK_SIZE])
wire (VIDNN 1)    		VIGainSelector ([IO_SAMPLE_RATE] 2 [IO_BLOCK_SIZE])

; Extract Noise from Voice + Noise --> Noise = Ambient - Voice
wire (VIRESSplit 1)       (NoiseExtractDiff 0) ([IO_SAMPLE_RATE] 1 [IO_BLOCK_SIZE])
wire (VIRESSplit 0)       (NoiseExtractDiff 1) ([IO_SAMPLE_RATE] 1 [IO_BLOCK_SIZE])

; ===============================================================================
; Speech and noise shaping EQ
; ===============================================================================
wire (VIRESSplit 0)			(SpeechNoiseEQJoiner 0) ([IO_SAMPLE_RATE] 1 [IO_BLOCK_SIZE])
wire (NoiseExtractDiff)		(SpeechNoiseEQJoiner 1) ([IO_SAMPLE_RATE] 1 [IO_BLOCK_SIZE])
wire SpeechNoiseEQJoiner	SpeechNoiseEQ			([IO_SAMPLE_RATE] 2 [IO_BLOCK_SIZE])
wire SpeechNoiseEQ 			SpeechNoiseEQSplitter   ([IO_SAMPLE_RATE] 2 [IO_BLOCK_SIZE])

; ===============================================================================
; Adaptive mix of speech and ambience
; ===============================================================================
wire (SpeechNoiseEQSplitter 0) 		(VoiceAmbMix 0)   ([IO_SAMPLE_RATE] 1 [IO_BLOCK_SIZE])
wire (SpeechNoiseEQSplitter 1) 		AmbGain      	  ([IO_SAMPLE_RATE] 1 [IO_BLOCK_SIZE])
wire AmbGain      					(VoiceAmbMix 1)   ([IO_SAMPLE_RATE] 1 [IO_BLOCK_SIZE])

wire VoiceAmbMix MixFFT ([IO_SAMPLE_RATE] 1 [IO_BLOCK_SIZE])

; Align VI input with VI output
wire (Mic1LECV5 1) VIAlignInputEclee ([IO_SAMPLE_RATE] 1 [IO_BLOCK_SIZE])
wire (Mic1LECV5 2) VIAlignRefInput ([IO_SAMPLE_RATE] 1 [IO_BLOCK_SIZE])

; ===============================================================================
; Mixed Signal: Echo gate
; ===============================================================================
wire VIAlignInputEclee VIEcleeFFT ([IO_SAMPLE_RATE] 1 [IO_BLOCK_SIZE])
wire VIAlignRefInput GateRefFFT ([IO_SAMPLE_RATE] 1 [IO_BLOCK_SIZE])
wire MixFFT (GateV3 [kAUEchoGateV3_EsOutInputBus]) (freq [IO_SAMPLE_RATE] 1 [IO_BLOCK_SIZE]) 
wire GateRefFFT (GateV3 [kAUEchoGateV3_TimeAlignedRefInputBus]) (freq [IO_SAMPLE_RATE] 1 [IO_BLOCK_SIZE]) ; ref signal 
wire (Mic1LECV5 0) (GateV3 [kAUEchoGateV3_EcoEstInputBus]) ([IO_SAMPLE_RATE] 1 [IO_BLOCK_SIZE]) ; time-domain input used to establish formats only
wire VIEcleeFFT (GateV3 [kAUEchoGateV3_EcoEstInputBusFreq]) (freq [IO_SAMPLE_RATE] 1 [IO_BLOCK_SIZE]) ; linear echo estimate in freq
wire UnityGain (GateV3 [kAUEchoGateV3_ResGainInputBus]) ([IO_SAMPLE_RATE] 1 [IO_BLOCK_SIZE]) ; RES gain
wire VIGainSelector (GateV3 [kAUEchoGateV3_NetSuppGainInputBus]) ([IO_SAMPLE_RATE] 1 [IO_BLOCK_SIZE]) ; net suppression gain
wire GateV3 GateV3OutDeadEnd ([IO_SAMPLE_RATE] 1 [IO_BLOCK_SIZE])

; Apply gate gain
wire VoiceAmbMix gateGain ([IO_SAMPLE_RATE] 1 [IO_BLOCK_SIZE])

; Echo VAD is low when echo is present, high when echo is absent or during DT
; The goal is to use a gain of 1 during DT and when no echo is present
param evth 0.8 ; echo VAD threshold to decide whether to use gate or not.
wireParam (VIDNN [kAUNeuralNetSignalProbability]) (echo_absent 0 input 0)
wireGraphParam evth (echo_absent 0 input 1)
wireParam (echo_absent 0 output 0) (gateGainOverride 0 input 0)
wireParam (GateV3 [kAUEchoGateV3Param_CurrentGateScale]) (gateGainOverride 0 input 1)
wireParam (gateGainOverride 0 output 0) (gateGain 0 0 0)

; Wide Spectrum processing in absence of echo
param ecth -200 ; echo presence threshold to decide on VIDNN usage
wireParam (Mic1LECV5 [EC_EcleeEnergy]) (eclee_present 0 input 0) true
wireGraphParam ecth (eclee_present 0 input 1)
wireParam (eclee_present 0 output 0) (eclee_present_prop 0 input 0) true
wireProperty (eclee_present_prop ui32 output 0) (PathSelector slcm)

wire (Mic1LECV5 0) VIAlignInput	  		  ([IO_SAMPLE_RATE] 1 [IO_BLOCK_SIZE])
wire VIAlignInput  (PathSelectorJoiner 0) ([IO_SAMPLE_RATE] 1 [IO_BLOCK_SIZE])
wire gateGain 	   (PathSelectorJoiner 1) ([IO_SAMPLE_RATE] 1 [IO_BLOCK_SIZE])
wire PathSelectorJoiner PathSelector 	  ([IO_SAMPLE_RATE] 2 [IO_BLOCK_SIZE])

; ===============================================================================
; VAD to support RESs and AGC
; ===============================================================================
wire PathSelector  VAD    ([IO_SAMPLE_RATE] 1 [IO_BLOCK_SIZE])
wire VAD VADDeadEnd  ([IO_SAMPLE_RATE] 1 [IO_BLOCK_SIZE])

; ===============================================================================
; Output AU chain
; ===============================================================================
wire PathSelector Mute     ([IO_SAMPLE_RATE] 1 [IO_BLOCK_SIZE])
wire Mute Deesser      ([IO_SAMPLE_RATE] 1 [IO_BLOCK_SIZE])
wire Deesser AGCV2   ([IO_SAMPLE_RATE] 1 [IO_BLOCK_SIZE])
wire AGCV2 MicOutput ([IO_SAMPLE_RATE] 1 [IO_BLOCK_SIZE])

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; 	Parameters
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
param uior 0 in ; vp::vx::Graph_Parameter_ID::UI_Orientation
wireGraphParam uior (GateV3 [kAUEchoGateV3Param_PlayBackScenario])

param ulvm 0 in ; vp::vx::Graph_Parameter_ID::Uplink_Near_End_Voice_Output_Mute
wireGraphParam ulvm (Mute 1)

param dlgn 0 in ; downlink gain (dB)
wireGraphParam dlgn (GateV3 [kAUEchoGateV3Param_CurrDLGain])

param uspb 0 out ; vp::vx::Graph_Parameter_ID::Uplink_Speech_Probability_Boolean_Value
wireGraphParam uspb (VAD uspb)

param uspf 0 out ; vp::vx::Graph_Parameter_ID::Uplink_Speech_Probability_Float_Value
wireGraphParam uspf (VAD uspf)

param unit 1 in ; unity constant parameter (generic unit)
wireGraphParam unit (UnityGain 0) ; zero input

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; 	Parameter wires
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Parameters to Gate
wireParam (Mic1LECV5 [EC_RelativeDeltaEIR]) (GateV3 [kAUEchoGateV3Param_RelativeDeltaEIR]) true
wireParam (Mic1LECV5 [EC_IRDelay]) (GateV3 [kAUEchoGateV3Param_IRDelay]) true
wireParam (AGCV2 [kAUAGCV2Param_CurrentGainDb]) (GateV3 [kAUEchoGateV3Param_AGCGain])
wireParam (AGCV2 [kAUAGCV2Param_PostGainDb]) (GateV3 [kAUEchoGateV3Param_PostGain])

; Parameters to AGC 
wireParam (VAD uspb) (AGCV2 [kAUAGCV2Param_ExtVadSpeechProbability]) true

; Delay for parallel paths
wireParam (VIDNN [kAUNeuralNetLatencySamples]) (VIAlignInputEclee 0 0 0)
wireParam (VIDNN [kAUNeuralNetLatencySamples]) (VIAlignRefInput 0 0 0)
wireParam (VIDNN [kAUNeuralNetLatencySamples]) (VIAlignInput 0 0 0)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; 	Properties
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

property agcb in ; vp::vx::Graph_Property_ID::Uplink_AGC_Bypass
wireGraphProperty agcb (AGCV2 [kAudioUnitProperty_BypassEffect])

property tudp in ; vp::vx::Graph_Property_ID::Tuning_Directory_Path
wireGraphProperty tudp (VAD [kAUDSPGraphProperty_PropertyStripResourcePath])
wireGraphProperty tudp (VIDNN [kAUNeuralNetParam_NeuralNetModelPathBaseOverride])
