From ee40a2e7e4867a769765d447a15ac88832eb8aa0 Mon Sep 17 00:00:00 2001
From: Chris Robinson <chris.kcat@gmail.com>
Date: Fri, 21 Oct 2022 10:33:41 -0700
Subject: Add an IIR filter option for UHJ encoding/decoding

This uses the reversed-allpass trick to maintain linear phase. with a 256-
sample look-ahead/delay to minimize distortion. This should better preserve low
frequencies while maintaining a proper phase response.
---
 core/voice.cpp | 53 ++++++++++++++++++++++++++++++-----------------------
 1 file changed, 30 insertions(+), 23 deletions(-)

(limited to 'core/voice.cpp')

diff --git a/core/voice.cpp b/core/voice.cpp
index 74363fc1..ae8582da 100644
--- a/core/voice.cpp
+++ b/core/voice.cpp
@@ -852,37 +852,44 @@ void Voice::prepare(DeviceBase *device)
     mPrevSamples.reserve(maxu(2, num_channels));
     mPrevSamples.resize(num_channels);
 
+    mDecoder = nullptr;
+    mDecoderPadding = 0;
     if(mFmtChannels == FmtSuperStereo)
     {
-        if(UhjQuality >= UhjLengthHq)
-        {
-            mDecoder = std::make_unique<UhjStereoDecoder<UhjLengthHq>>();
-            mDecoderPadding = UhjStereoDecoder<UhjLengthHq>::sFilterDelay;
-        }
-        else
+        switch(UhjQuality)
         {
+        case UhjQualityType::IIR:
+            mDecoder = std::make_unique<UhjStereoDecoderIIR>();
+            mDecoderPadding = UhjStereoDecoderIIR::sFilterDelay;
+            break;
+        case UhjQualityType::FIR256:
             mDecoder = std::make_unique<UhjStereoDecoder<UhjLengthLq>>();
             mDecoderPadding = UhjStereoDecoder<UhjLengthLq>::sFilterDelay;
+            break;
+        case UhjQualityType::FIR512:
+            mDecoder = std::make_unique<UhjStereoDecoder<UhjLengthHq>>();
+            mDecoderPadding = UhjStereoDecoder<UhjLengthHq>::sFilterDelay;
+            break;
         }
     }
     else if(IsUHJ(mFmtChannels))
     {
-        if(UhjQuality >= UhjLengthHq)
-        {
-            mDecoder = std::make_unique<UhjDecoder<UhjLengthHq>>();
-            mDecoderPadding = UhjDecoder<UhjLengthHq>::sFilterDelay;
-        }
-        else
+        switch(UhjQuality)
         {
+        case UhjQualityType::IIR:
+            mDecoder = std::make_unique<UhjDecoderIIR>();
+            mDecoderPadding = UhjDecoderIIR::sFilterDelay;
+            break;
+        case UhjQualityType::FIR256:
             mDecoder = std::make_unique<UhjDecoder<UhjLengthLq>>();
             mDecoderPadding = UhjDecoder<UhjLengthLq>::sFilterDelay;
+            break;
+        case UhjQualityType::FIR512:
+            mDecoder = std::make_unique<UhjDecoder<UhjLengthHq>>();
+            mDecoderPadding = UhjDecoder<UhjLengthHq>::sFilterDelay;
+            break;
         }
     }
-    else
-    {
-        mDecoder = nullptr;
-        mDecoderPadding = 0;
-    }
 
     /* Clear the stepping value explicitly so the mixer knows not to mix this
      * until the update gets applied.
@@ -925,11 +932,11 @@ void Voice::prepare(DeviceBase *device)
         if(mFmtChannels == FmtUHJ2)
         {
             mChans[0].mAmbiHFScale = 1.0f;
-            mChans[0].mAmbiLFScale = UhjDecoder<UhjLengthStd>::sWLFScale;
+            mChans[0].mAmbiLFScale = DecoderBase::sWLFScale;
             mChans[1].mAmbiHFScale = 1.0f;
-            mChans[1].mAmbiLFScale = UhjDecoder<UhjLengthStd>::sXYLFScale;
+            mChans[1].mAmbiLFScale = DecoderBase::sXYLFScale;
             mChans[2].mAmbiHFScale = 1.0f;
-            mChans[2].mAmbiLFScale = UhjDecoder<UhjLengthStd>::sXYLFScale;
+            mChans[2].mAmbiLFScale = DecoderBase::sXYLFScale;
         }
         mFlags.set(VoiceIsAmbisonic);
     }
@@ -949,9 +956,9 @@ void Voice::prepare(DeviceBase *device)
             chandata.mDryParams.NFCtrlFilter = device->mNFCtrlFilter;
             std::fill_n(chandata.mWetParams.begin(), device->NumAuxSends, SendParams{});
         }
-        mChans[0].mAmbiLFScale = UhjDecoder<UhjLengthStd>::sWLFScale;
-        mChans[1].mAmbiLFScale = UhjDecoder<UhjLengthStd>::sXYLFScale;
-        mChans[2].mAmbiLFScale = UhjDecoder<UhjLengthStd>::sXYLFScale;
+        mChans[0].mAmbiLFScale = DecoderBase::sWLFScale;
+        mChans[1].mAmbiLFScale = DecoderBase::sXYLFScale;
+        mChans[2].mAmbiLFScale = DecoderBase::sXYLFScale;
         mFlags.set(VoiceIsAmbisonic);
     }
     else
-- 
cgit v1.2.3