bug 1476231 switch FFTBlock from libav to ffvpx r?jya draft
authorKarl Tomlinson <karlt+@karlt.net>
Sat, 14 Jul 2018 14:44:43 +1200
changeset 825592 80c679073521f2e6c613694708594df50b539017
parent 825591 9645063a4bd139de0e149bcc346bce437c72bf33
child 825593 3b719451e40f732936b7a119fba72ce7dee9fac2
push id118144
push userktomlinson@mozilla.com
push dateThu, 02 Aug 2018 02:57:58 +0000
reviewersjya
bugs1476231
milestone63.0a1
bug 1476231 switch FFTBlock from libav to ffvpx r?jya This results in a speed improvement of about 6% on the "Convolution reverb" webaudio-benchmark (measured with Linux x86_64 build on Skylake). MozReview-Commit-ID: 94W6h3qE1tB
dom/media/webaudio/AudioContext.cpp
dom/media/webaudio/FFTBlock.cpp
dom/media/webaudio/FFTBlock.h
testing/web-platform/meta/webaudio/the-audio-api/the-convolvernode-interface/convolver-response-1-chan.html.ini
testing/web-platform/meta/webaudio/the-audio-api/the-convolvernode-interface/convolver-response-2-chan.html.ini
testing/web-platform/meta/webaudio/the-audio-api/the-convolvernode-interface/convolver-response-4-chan.html.ini
--- a/dom/media/webaudio/AudioContext.cpp
+++ b/dom/media/webaudio/AudioContext.cpp
@@ -172,16 +172,18 @@ AudioContext::AudioContext(nsPIDOMWindow
   // in order to delay the state changing from 'suspend' to 'start'.
   if (!allowedToStart) {
     ErrorResult rv;
     RefPtr<Promise> dummy = Suspend(rv);
     MOZ_ASSERT(!rv.Failed(), "can't create promise");
     MOZ_ASSERT(dummy->State() != Promise::PromiseState::Rejected,
                "suspend failed");
   }
+
+  FFTBlock::MainThreadInit();
 }
 
 nsresult
 AudioContext::Init()
 {
   if (!mIsOffline) {
     nsresult rv = mDestination->CreateAudioChannelAgent();
     if (NS_WARN_IF(NS_FAILED(rv))) {
--- a/dom/media/webaudio/FFTBlock.cpp
+++ b/dom/media/webaudio/FFTBlock.cpp
@@ -31,16 +31,20 @@
 #include "FFTBlock.h"
 
 #include <complex>
 
 namespace mozilla {
 
 typedef std::complex<double> Complex;
 
+#ifdef MOZ_LIBAV_FFT
+FFmpegRDFTFuncs FFTBlock::sRDFTFuncs;
+#endif
+
 FFTBlock* FFTBlock::CreateInterpolatedBlock(const FFTBlock& block0, const FFTBlock& block1, double interp)
 {
     FFTBlock* newBlock = new FFTBlock(block0.FFTSize());
 
     newBlock->InterpolateFrequencyComponents(block0, block1, interp);
 
     // In the time-domain, the 2nd half of the response must be zero, to avoid circular convolution aliasing...
     int fftSize = newBlock->FFTSize();
--- a/dom/media/webaudio/FFTBlock.h
+++ b/dom/media/webaudio/FFTBlock.h
@@ -11,23 +11,18 @@
 #include <cmath>
 #include "mozilla/arm.h"
 #include "dl/sp/api/omxSP.h"
 #endif
 
 #include "AlignedTArray.h"
 #include "AudioNodeEngine.h"
 #if defined(MOZ_LIBAV_FFT)
-#ifdef __cplusplus
-extern "C" {
-#endif
-#include "libavcodec/avfft.h"
-#ifdef __cplusplus
-}
-#endif
+#include "FFmpegRDFTTypes.h"
+#include "FFVPXRuntimeLinker.h"
 #else
 #include "kiss_fft/kiss_fftr.h"
 #endif
 
 namespace mozilla {
 
 // This class defines an FFT block, loosely modeled after Blink's FFTFrame
 // class to make sharing code with Blink easy.
@@ -41,16 +36,24 @@ class FFTBlock final
     float f[2];
     struct {
       float r;
       float i;
     };
   };
 
 public:
+  static void MainThreadInit()
+  {
+#ifdef MOZ_LIBAV_FFT
+    FFVPXRuntimeLinker::Init();
+    FFVPXRuntimeLinker::GetRDFTFuncs(&sRDFTFuncs);
+#endif
+  }
+
   explicit FFTBlock(uint32_t aFFTSize)
 #if defined(MOZ_LIBAV_FFT)
     : mAvRDFT(nullptr)
     , mAvIRDFT(nullptr)
 #else
     : mKissFFT(nullptr)
     , mKissIFFT(nullptr)
 #ifdef BUILD_ARM_NEON
@@ -72,20 +75,23 @@ public:
   // |block0| and |block1| with |interp| between 0.0 and 1.0.
   static FFTBlock*
   CreateInterpolatedBlock(const FFTBlock& block0,
                           const FFTBlock& block1, double interp);
 
   // Transform FFTSize() points of aData and store the result internally.
   void PerformFFT(const float* aData)
   {
-    EnsureFFT();
+    if (!EnsureFFT()) {
+      return;
+    }
+
 #if defined(MOZ_LIBAV_FFT)
     PodCopy(mOutputBuffer.Elements()->f, aData, mFFTSize);
-    av_rdft_calc(mAvRDFT, mOutputBuffer.Elements()->f);
+    sRDFTFuncs.calc(mAvRDFT, mOutputBuffer.Elements()->f);
     // Recover packed Nyquist.
     mOutputBuffer[mFFTSize / 2].r = mOutputBuffer[0].i;
     mOutputBuffer[0].i = 0.0f;
 #else
 #ifdef BUILD_ARM_NEON
     if (mozilla::supports_neon()) {
       omxSP_FFTFwd_RToCCS_F32_Sfs(aData, mOutputBuffer.Elements()->f, mOmxFFT);
     } else
@@ -97,31 +103,36 @@ public:
   }
   // Inverse-transform internal data and store the resulting FFTSize()
   // points in aDataOut.
   void GetInverse(float* aDataOut)
   {
     GetInverseWithoutScaling(aDataOut);
     AudioBufferInPlaceScale(aDataOut, 1.0f / mFFTSize, mFFTSize);
   }
+
   // Inverse-transform internal frequency data and store the resulting
   // FFTSize() points in |aDataOut|.  If frequency data has not already been
   // scaled, then the output will need scaling by 1/FFTSize().
   void GetInverseWithoutScaling(float* aDataOut)
   {
-    EnsureIFFT();
+    if (!EnsureIFFT()) {
+      std::fill_n(aDataOut, mFFTSize, 0.0f);
+      return;
+    };
+
 #if defined(MOZ_LIBAV_FFT)
     {
       // Even though this function doesn't scale, the libav forward transform
       // gives a value that needs scaling by 2 in order for things to turn out
       // similar to how we expect from kissfft/openmax.
       AudioBufferCopyWithScale(mOutputBuffer.Elements()->f, 2.0f,
                                aDataOut, mFFTSize);
       aDataOut[1] = 2.0f * mOutputBuffer[mFFTSize/2].r; // Packed Nyquist
-      av_rdft_calc(mAvIRDFT, aDataOut);
+      sRDFTFuncs.calc(mAvIRDFT, aDataOut);
     }
 #else
 #ifdef BUILD_ARM_NEON
     if (mozilla::supports_neon()) {
       omxSP_FFTInv_CCSToR_F32_Sfs_unscaled(mOutputBuffer.Elements()->f, aDataOut, mOmxIFFT);
     } else
 #endif
     {
@@ -211,57 +222,68 @@ public:
   {
     return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
   }
 
 private:
   FFTBlock(const FFTBlock& other) = delete;
   void operator=(const FFTBlock& other) = delete;
 
-  void EnsureFFT()
+  bool EnsureFFT()
   {
 #if defined(MOZ_LIBAV_FFT)
     if (!mAvRDFT) {
-      mAvRDFT = av_rdft_init(log((double)mFFTSize)/M_LN2, DFT_R2C);
+      if (!sRDFTFuncs.init) {
+        return false;
+      }
+
+      mAvRDFT = sRDFTFuncs.init(log((double)mFFTSize)/M_LN2, DFT_R2C);
     }
 #else
 #ifdef BUILD_ARM_NEON
     if (mozilla::supports_neon()) {
       if (!mOmxFFT) {
         mOmxFFT = createOmxFFT(mFFTSize);
       }
     } else
 #endif
     {
       if (!mKissFFT) {
         mKissFFT = kiss_fftr_alloc(mFFTSize, 0, nullptr, nullptr);
       }
     }
 #endif
+    return true;
   }
-  void EnsureIFFT()
+
+  bool EnsureIFFT()
   {
 #if defined(MOZ_LIBAV_FFT)
     if (!mAvIRDFT) {
-      mAvIRDFT = av_rdft_init(log((double)mFFTSize)/M_LN2, IDFT_C2R);
+      if (!sRDFTFuncs.init) {
+        return false;
+      }
+
+      mAvIRDFT = sRDFTFuncs.init(log((double)mFFTSize)/M_LN2, IDFT_C2R);
     }
 #else
 #ifdef BUILD_ARM_NEON
     if (mozilla::supports_neon()) {
       if (!mOmxIFFT) {
         mOmxIFFT = createOmxFFT(mFFTSize);
       }
     } else
 #endif
     {
       if (!mKissIFFT) {
         mKissIFFT = kiss_fftr_alloc(mFFTSize, 1, nullptr, nullptr);
       }
     }
 #endif
+    return true;
   }
 
 #ifdef BUILD_ARM_NEON
   static OMXFFTSpec_R_F32* createOmxFFT(uint32_t aFFTSize)
   {
     MOZ_ASSERT((aFFTSize & (aFFTSize-1)) == 0);
     OMX_INT bufSize;
     OMX_INT order = log((double)aFFTSize)/M_LN2;
@@ -276,34 +298,40 @@ private:
     }
     return nullptr;
   }
 #endif
 
   void Clear()
   {
 #if defined(MOZ_LIBAV_FFT)
-    av_rdft_end(mAvRDFT);
-    av_rdft_end(mAvIRDFT);
-    mAvRDFT = mAvIRDFT = nullptr;
+    if (mAvRDFT) {
+      sRDFTFuncs.end(mAvRDFT);
+      mAvRDFT = nullptr;
+    }
+    if (mAvIRDFT) {
+      sRDFTFuncs.end(mAvIRDFT);
+      mAvIRDFT = nullptr;
+    }
 #else
 #ifdef BUILD_ARM_NEON
     free(mOmxFFT);
     free(mOmxIFFT);
     mOmxFFT = mOmxIFFT = nullptr;
 #endif
     free(mKissFFT);
     free(mKissIFFT);
     mKissFFT = mKissIFFT = nullptr;
 #endif
   }
   void AddConstantGroupDelay(double sampleFrameDelay);
   void InterpolateFrequencyComponents(const FFTBlock& block0,
                                       const FFTBlock& block1, double interp);
 #if defined(MOZ_LIBAV_FFT)
+  static FFmpegRDFTFuncs sRDFTFuncs;
   RDFTContext *mAvRDFT;
   RDFTContext *mAvIRDFT;
 #else
   kiss_fftr_cfg mKissFFT;
   kiss_fftr_cfg mKissIFFT;
 #ifdef BUILD_ARM_NEON
   OMXFFTSpec_R_F32* mOmxFFT;
   OMXFFTSpec_R_F32* mOmxIFFT;
--- a/testing/web-platform/meta/webaudio/the-audio-api/the-convolvernode-interface/convolver-response-1-chan.html.ini
+++ b/testing/web-platform/meta/webaudio/the-audio-api/the-convolvernode-interface/convolver-response-1-chan.html.ini
@@ -1,10 +1,10 @@
 [convolver-response-1-chan.html]
-  [X 1: Channel 1: Expected 0 for all values but found 1280 unexpected values: \n\tIndex\tActual\n\t[0\]\t-1.4901161193847656e-7\n\t[1\]\t-8.940696716308594e-8\n\t[2\]\t0.3311062455177307\n\t[3\]\t0.6248594522476196\n\t...and 1276 more errors.]
+  [X 1: Channel 1: Expected 0 for all values but found 1280 unexpected values: \n\tIndex\tActual\n\t[0\]\t-1.1920928955078125e-7\n\t[1\]\t-4.470348358154297e-8\n\t[2\]\t0.3311062455177307\n\t[3\]\t0.6248593926429749\n\t...and 1276 more errors.]
     expected: FAIL
 
   [< [1-channel input\] 1 out of 2 assertions were failed.]
     expected: FAIL
 
   [X 2: Channel 0 expected to be equal to the array [0,0,0.9458408951759338,0.8448333740234375,0.8210252523422241,0.8620985746383667,0.8430315852165222,0.855602502822876,0.7933436632156372,0.9865825176239014,0.3972480297088623,-0.7786127924919128,-0.9223549962043762,-0.7896472215652466,-0.8727429509162903,-0.8325281143188477...\] but differs in 1276 places:\n\tIndex\tActual\t\t\tExpected\n\t[2\]\t0.0000000000000000e+0\t9.4584089517593384e-1\n\t[3\]\t0.0000000000000000e+0\t8.4483337402343750e-1\n\t[4\]\t0.0000000000000000e+0\t8.2102525234222412e-1\n\t[5\]\t0.0000000000000000e+0\t8.6209857463836670e-1\n\t...and 1272 more errors.]
     expected: FAIL
 
--- a/testing/web-platform/meta/webaudio/the-audio-api/the-convolvernode-interface/convolver-response-2-chan.html.ini
+++ b/testing/web-platform/meta/webaudio/the-audio-api/the-convolvernode-interface/convolver-response-2-chan.html.ini
@@ -9,8 +9,32 @@
     expected: FAIL
 
   [< [4-channel input\] 1 out of 2 assertions were failed.]
     expected: FAIL
 
   [# AUDIT TASK RUNNER FINISHED: 2 out of 6 tasks were failed.]
     expected: FAIL
 
+  [X 1: Channel 0 does not equal [0,0,0.9458408951759338,0.8448333740234375,0.8210252523422241,0.8620985746383667,0.8430315852165222,0.855602502822876,0.7933436632156372,0.9865825176239014,0.3972480297088623,-0.7786127924919128,-0.9223549962043762,-0.7896472215652466,-0.8727429509162903,-0.8325281143188477...\] with an element-wise tolerance of {"absoluteThreshold":3.5763e-7,"relativeThreshold":0}.\n\tIndex\tActual\t\t\tExpected\t\tAbsError\t\tRelError\t\tTest threshold\n\t[267\]\t8.6412906646728516e-1\t8.6412948369979858e-1\t4.1723251342773438e-7\t4.8283564129919487e-7\t3.5763000000000001e-7\n\t[779\]\t-8.6412906646728516e-1\t-8.6412948369979858e-1\t4.1723251342773438e-7\t4.8283564129919487e-7\t3.5763000000000001e-7\n\tMax AbsError of 4.1723251342773438e-7 at index of 267.\n\tMax RelError of 4.8283564129919487e-7 at index of 267.\n]
+    expected: FAIL
+
+  [< [1-channel input\] 1 out of 2 assertions were failed.]
+    expected: FAIL
+
+  [X 2: Channel 0 does not equal [0,0,0.9458408951759338,0.8448333740234375,0.8210252523422241,0.8620985746383667,0.8430315852165222,0.855602502822876,0.7933436632156372,0.9865825176239014,0.3972480297088623,-0.7786127924919128,-0.9223549962043762,-0.7896472215652466,-0.8727429509162903,-0.8325281143188477...\] with an element-wise tolerance of {"absoluteThreshold":3.5763e-7,"relativeThreshold":0}.\n\tIndex\tActual\t\t\tExpected\t\tAbsError\t\tRelError\t\tTest threshold\n\t[267\]\t8.6412906646728516e-1\t8.6412948369979858e-1\t4.1723251342773438e-7\t4.8283564129919487e-7\t3.5763000000000001e-7\n\t[779\]\t-8.6412906646728516e-1\t-8.6412948369979858e-1\t4.1723251342773438e-7\t4.8283564129919487e-7\t3.5763000000000001e-7\n\tMax AbsError of 4.1723251342773438e-7 at index of 267.\n\tMax RelError of 4.8283564129919487e-7 at index of 267.\n]
+    expected: FAIL
+
+  [< [2-channel input\] 1 out of 2 assertions were failed.]
+    expected: FAIL
+
+  [X 3: Channel 0 does not equal [0,0,0.9458408951759338,0.8448333740234375,0.8210252523422241,0.8620985746383667,0.8430315852165222,0.855602502822876,0.7933436632156372,0.9865825176239014,0.3972480297088623,-0.7786127924919128,-0.9223549962043762,-0.7896472215652466,-0.8727429509162903,-0.8325281143188477...\] with an element-wise tolerance of {"absoluteThreshold":3.5763e-7,"relativeThreshold":0}.\n\tIndex\tActual\t\t\tExpected\t\tAbsError\t\tRelError\t\tTest threshold\n\t[267\]\t8.6412906646728516e-1\t8.6412948369979858e-1\t4.1723251342773438e-7\t4.8283564129919487e-7\t3.5763000000000001e-7\n\t[779\]\t-8.6412906646728516e-1\t-8.6412948369979858e-1\t4.1723251342773438e-7\t4.8283564129919487e-7\t3.5763000000000001e-7\n\tMax AbsError of 4.1723251342773438e-7 at index of 267.\n\tMax RelError of 4.8283564129919487e-7 at index of 267.\n]
+    expected: FAIL
+
+  [X 3: Channel 1 does not equal [0,0,0,0.9918842315673828,0.7683960199356079,0.9083511829376221,0.7684863805770874,0.9814503192901611,0.3193226158618927,-0.9322392344474792,-0.8032255172729492,-0.8812425136566162,-0.7985008358955383,-0.9260328412055969,-0.600982666015625,0.7887306809425354...\] with an element-wise tolerance of {"absoluteThreshold":3.5763e-7,"relativeThreshold":0}.\n\tIndex\tActual\t\t\tExpected\t\tAbsError\t\tRelError\t\tTest threshold\n\t[653\]\t8.3021926879882813e-1\t8.3021968603134155e-1\t4.1723251342773438e-7\t5.0255675750380060e-7\t3.5763000000000001e-7\n\t[1001\]\t2.7387520670890808e-1\t2.7387481927871704e-1\t3.8743019104003906e-7\t1.4146250906176189e-6\t3.5763000000000001e-7\n\tMax AbsError of 4.1723251342773438e-7 at index of 653.\n\tMax RelError of 1.4146250906176189e-6 at index of 1001.\n]
+    expected: FAIL
+
+  [< [3-channel input\] 2 out of 2 assertions were failed.]
+    expected: FAIL
+
+  [# AUDIT TASK RUNNER FINISHED: 3 out of 6 tasks were failed.]
+    expected: FAIL
+
--- a/testing/web-platform/meta/webaudio/the-audio-api/the-convolvernode-interface/convolver-response-4-chan.html.ini
+++ b/testing/web-platform/meta/webaudio/the-audio-api/the-convolvernode-interface/convolver-response-4-chan.html.ini
@@ -40,38 +40,38 @@
     expected: FAIL
 
   [X 5.1: Channel 1 expected to be equal to the array [0,0,0,2.2955894470214844,2.0720269680023193,3.932274580001831,2.6799838542938232,1.030521035194397,0.5735810399055481,1.1953468322753906,1.1813759803771973,-0.4176444709300995,-2.2066140174865723,-2.9535813331604004,-1.2753634452819824,0.26151078939437866...\] but differs in 1023 places:\n\tIndex\tActual\t\t\tExpected\n\t[0\]\t-1.6391277313232422e-7\t0.0000000000000000e+0\n\t[1\]\t-2.9802322387695313e-7\t0.0000000000000000e+0\n\t[2\]\t-7.0780515670776367e-8\t0.0000000000000000e+0\n\t[5\]\t3.9322743415832520e+0\t3.9322745800018311e+0\n\t...and 1019 more errors.]
     expected: FAIL
 
   [< [5.1-channel input\] 2 out of 2 assertions were failed.]
     expected: FAIL
 
-  [X 1: Channel 0 expected to be equal to the array [0,0,0.9458408951759338,0.8448333740234375,1.7668662071228027,1.7069319486618042,1.6640567779541016,1.7177010774612427,1.6363751888275146,1.8421850204467773,1.1905916929244995,0.20796972513198853,-0.5251069664955139,-1.5682599544525146,-1.7950979471206665,-1.6221753358840942...\] but differs in 965 places:\n\tIndex\tActual\t\t\tExpected\n\t[0\]\t-2.9802322387695313e-8\t0.0000000000000000e+0\n\t[1\]\t-7.4505805969238281e-8\t0.0000000000000000e+0\n\t[2\]\t9.4584065675735474e-1\t9.4584089517593384e-1\n\t[4\]\t1.7668659687042236e+0\t1.7668662071228027e+0\n\t...and 961 more errors.]
+  [X 1: Channel 0 expected to be equal to the array [0,0,0.9458408951759338,0.8448333740234375,1.7668662071228027,1.7069319486618042,1.6640567779541016,1.7177010774612427,1.6363751888275146,1.8421850204467773,1.1905916929244995,0.20796972513198853,-0.5251069664955139,-1.5682599544525146,-1.7950979471206665,-1.6221753358840942...\] but differs in 969 places:\n\tIndex\tActual\t\t\tExpected\n\t[0\]\t1.1920928955078125e-7\t0.0000000000000000e+0\n\t[1\]\t-7.4505805969238281e-8\t0.0000000000000000e+0\n\t[2\]\t9.4584071636199951e-1\t9.4584089517593384e-1\n\t[3\]\t8.4483325481414795e-1\t8.4483337402343750e-1\n\t...and 965 more errors.]
     expected: FAIL
 
-  [X 1: Channel 1 expected to be equal to the array [0,0,0,0.9458408951759338,0.8448333740234375,1.7668662071228027,1.7069319486618042,1.6640567779541016,1.7177010774612427,1.6363751888275146,1.8421850204467773,1.1905916929244995,0.20796972513198853,-0.5251069664955139,-1.5682599544525146,-1.7950979471206665...\] but differs in 983 places:\n\tIndex\tActual\t\t\tExpected\n\t[0\]\t-1.7881393432617188e-7\t0.0000000000000000e+0\n\t[1\]\t2.9802322387695313e-8\t0.0000000000000000e+0\n\t[2\]\t-1.0430812835693359e-7\t0.0000000000000000e+0\n\t[3\]\t9.4584077596664429e-1\t9.4584089517593384e-1\n\t...and 979 more errors.]
+  [X 1: Channel 1 expected to be equal to the array [0,0,0,0.9458408951759338,0.8448333740234375,1.7668662071228027,1.7069319486618042,1.6640567779541016,1.7177010774612427,1.6363751888275146,1.8421850204467773,1.1905916929244995,0.20796972513198853,-0.5251069664955139,-1.5682599544525146,-1.7950979471206665...\] but differs in 1011 places:\n\tIndex\tActual\t\t\tExpected\n\t[2\]\t-2.6077032089233398e-8\t0.0000000000000000e+0\n\t[3\]\t9.4584083557128906e-1\t9.4584089517593384e-1\n\t[4\]\t8.4483331441879272e-1\t8.4483337402343750e-1\n\t[5\]\t1.7668659687042236e+0\t1.7668662071228027e+0\n\t...and 1007 more errors.]
     expected: FAIL
 
-  [X 2: Channel 0 expected to be equal to the array [0,0,0.9458408951759338,0.8448333740234375,1.812909483909607,1.6304945945739746,1.751382827758789,1.6240888833999634,1.7747939825057983,1.3059051036834717,-0.5349912047386169,-1.5818383693695068,-1.8035974502563477,-1.5881481170654297,-1.7987757921218872,-1.4335107803344727...\] but differs in 991 places:\n\tIndex\tActual\t\t\tExpected\n\t[0\]\t-1.4901161193847656e-7\t0.0000000000000000e+0\n\t[1\]\t-1.0430812835693359e-7\t0.0000000000000000e+0\n\t[2\]\t9.4584071636199951e-1\t9.4584089517593384e-1\n\t[3\]\t8.4483331441879272e-1\t8.4483337402343750e-1\n\t...and 987 more errors.]
+  [X 2: Channel 0 expected to be equal to the array [0,0,0.9458408951759338,0.8448333740234375,1.812909483909607,1.6304945945739746,1.751382827758789,1.6240888833999634,1.7747939825057983,1.3059051036834717,-0.5349912047386169,-1.5818383693695068,-1.8035974502563477,-1.5881481170654297,-1.7987757921218872,-1.4335107803344727...\] but differs in 1032 places:\n\tIndex\tActual\t\t\tExpected\n\t[0\]\t-8.9406967163085938e-8\t0.0000000000000000e+0\n\t[1\]\t-1.9371509552001953e-7\t0.0000000000000000e+0\n\t[2\]\t9.4584083557128906e-1\t9.4584089517593384e-1\n\t[3\]\t8.4483325481414795e-1\t8.4483337402343750e-1\n\t...and 1028 more errors.]
     expected: FAIL
 
-  [X 2: Channel 1 expected to be equal to the array [0,0,0,0.9458408951759338,0.8448333740234375,1.812909483909607,1.6304945945739746,1.751382827758789,1.6240888833999634,1.7747939825057983,1.3059051036834717,-0.5349912047386169,-1.5818383693695068,-1.8035974502563477,-1.5881481170654297,-1.7987757921218872...\] but differs in 999 places:\n\tIndex\tActual\t\t\tExpected\n\t[0\]\t-1.7881393432617188e-7\t0.0000000000000000e+0\n\t[1\]\t-1.1920928955078125e-7\t0.0000000000000000e+0\n\t[2\]\t-2.5331974029541016e-7\t0.0000000000000000e+0\n\t[3\]\t9.4584071636199951e-1\t9.4584089517593384e-1\n\t...and 995 more errors.]
+  [X 2: Channel 1 expected to be equal to the array [0,0,0,0.9458408951759338,0.8448333740234375,1.812909483909607,1.6304945945739746,1.751382827758789,1.6240888833999634,1.7747939825057983,1.3059051036834717,-0.5349912047386169,-1.5818383693695068,-1.8035974502563477,-1.5881481170654297,-1.7987757921218872...\] but differs in 1003 places:\n\tIndex\tActual\t\t\tExpected\n\t[0\]\t-5.9604644775390625e-8\t0.0000000000000000e+0\n\t[1\]\t-1.4901161193847656e-7\t0.0000000000000000e+0\n\t[2\]\t-2.0489096641540527e-7\t0.0000000000000000e+0\n\t[3\]\t9.4584083557128906e-1\t9.4584089517593384e-1\n\t...and 999 more errors.]
     expected: FAIL
 
-  [X 3: Channel 0 expected to be equal to the array [0,0,0.9458408951759338,0.8448333740234375,1.812909483909607,1.6304945945739746,1.751382827758789,1.6240888833999634,1.7747939825057983,1.3059051036834717,-0.5349912047386169,-1.5818383693695068,-1.8035974502563477,-1.5881481170654297,-1.7987757921218872,-1.4335107803344727...\] but differs in 991 places:\n\tIndex\tActual\t\t\tExpected\n\t[0\]\t-1.4901161193847656e-7\t0.0000000000000000e+0\n\t[1\]\t-1.0430812835693359e-7\t0.0000000000000000e+0\n\t[2\]\t9.4584071636199951e-1\t9.4584089517593384e-1\n\t[3\]\t8.4483331441879272e-1\t8.4483337402343750e-1\n\t...and 987 more errors.]
+  [X 3: Channel 0 expected to be equal to the array [0,0,0.9458408951759338,0.8448333740234375,1.812909483909607,1.6304945945739746,1.751382827758789,1.6240888833999634,1.7747939825057983,1.3059051036834717,-0.5349912047386169,-1.5818383693695068,-1.8035974502563477,-1.5881481170654297,-1.7987757921218872,-1.4335107803344727...\] but differs in 1032 places:\n\tIndex\tActual\t\t\tExpected\n\t[0\]\t-8.9406967163085938e-8\t0.0000000000000000e+0\n\t[1\]\t-1.9371509552001953e-7\t0.0000000000000000e+0\n\t[2\]\t9.4584083557128906e-1\t9.4584089517593384e-1\n\t[3\]\t8.4483325481414795e-1\t8.4483337402343750e-1\n\t...and 1028 more errors.]
     expected: FAIL
 
-  [X 3: Channel 1 expected to be equal to the array [0,0,0,0.9458408951759338,0.8448333740234375,1.812909483909607,1.6304945945739746,1.751382827758789,1.6240888833999634,1.7747939825057983,1.3059051036834717,-0.5349912047386169,-1.5818383693695068,-1.8035974502563477,-1.5881481170654297,-1.7987757921218872...\] but differs in 999 places:\n\tIndex\tActual\t\t\tExpected\n\t[0\]\t-1.7881393432617188e-7\t0.0000000000000000e+0\n\t[1\]\t-1.1920928955078125e-7\t0.0000000000000000e+0\n\t[2\]\t-2.5331974029541016e-7\t0.0000000000000000e+0\n\t[3\]\t9.4584071636199951e-1\t9.4584089517593384e-1\n\t...and 995 more errors.]
+  [X 3: Channel 1 expected to be equal to the array [0,0,0,0.9458408951759338,0.8448333740234375,1.812909483909607,1.6304945945739746,1.751382827758789,1.6240888833999634,1.7747939825057983,1.3059051036834717,-0.5349912047386169,-1.5818383693695068,-1.8035974502563477,-1.5881481170654297,-1.7987757921218872...\] but differs in 1003 places:\n\tIndex\tActual\t\t\tExpected\n\t[0\]\t-5.9604644775390625e-8\t0.0000000000000000e+0\n\t[1\]\t-1.4901161193847656e-7\t0.0000000000000000e+0\n\t[2\]\t-2.0489096641540527e-7\t0.0000000000000000e+0\n\t[3\]\t9.4584083557128906e-1\t9.4584089517593384e-1\n\t...and 999 more errors.]
     expected: FAIL
 
-  [X 4: Channel 0 expected to be equal to the array [0,0,0.9706697463989258,0.8062858581542969,1.8264563083648682,1.6379892826080322,1.0640915632247925,0.11066664755344391,0.0652712881565094,-0.2920137643814087,-0.7946902513504028,-0.007852882146835327,-0.029863953590393066,0.06670215725898743,-0.27740323543548584,-1.19685959815979...\] but differs in 1063 places:\n\tIndex\tActual\t\t\tExpected\n\t[0\]\t-6.3329935073852539e-8\t0.0000000000000000e+0\n\t[1\]\t-7.4505805969238281e-9\t0.0000000000000000e+0\n\t[6\]\t1.0640916824340820e+0\t1.0640915632247925e+0\n\t[7\]\t1.1066661775112152e-1\t1.1066664755344391e-1\n\t...and 1059 more errors.]
+  [X 4: Channel 0 expected to be equal to the array [0,0,0.9706697463989258,0.8062858581542969,1.8264563083648682,1.6379892826080322,1.0640915632247925,0.11066664755344391,0.0652712881565094,-0.2920137643814087,-0.7946902513504028,-0.007852882146835327,-0.029863953590393066,0.06670215725898743,-0.27740323543548584,-1.19685959815979...\] but differs in 1056 places:\n\tIndex\tActual\t\t\tExpected\n\t[1\]\t-4.4703483581542969e-8\t0.0000000000000000e+0\n\t[2\]\t9.7066980600357056e-1\t9.7066974639892578e-1\n\t[3\]\t8.0628573894500732e-1\t8.0628585815429688e-1\n\t[5\]\t1.6379891633987427e+0\t1.6379892826080322e+0\n\t...and 1052 more errors.]
     expected: FAIL
 
-  [X 4: Channel 1 expected to be equal to the array [0,0,0,0.9706697463989258,0.8062858581542969,1.8264563083648682,1.6379892826080322,1.0640915632247925,0.11066664755344391,0.0652712881565094,-0.2920137643814087,-0.7946902513504028,-0.007852882146835327,-0.029863953590393066,0.06670215725898743,-0.27740323543548584...\] but differs in 1063 places:\n\tIndex\tActual\t\t\tExpected\n\t[1\]\t-5.4016709327697754e-8\t0.0000000000000000e+0\n\t[2\]\t4.1909515857696533e-8\t0.0000000000000000e+0\n\t[3\]\t9.7066986560821533e-1\t9.7066974639892578e-1\n\t[4\]\t8.0628573894500732e-1\t8.0628585815429688e-1\n\t...and 1059 more errors.]
+  [X 4: Channel 1 expected to be equal to the array [0,0,0,0.9706697463989258,0.8062858581542969,1.8264563083648682,1.6379892826080322,1.0640915632247925,0.11066664755344391,0.0652712881565094,-0.2920137643814087,-0.7946902513504028,-0.007852882146835327,-0.029863953590393066,0.06670215725898743,-0.27740323543548584...\] but differs in 1060 places:\n\tIndex\tActual\t\t\tExpected\n\t[0\]\t2.9802322387695313e-8\t0.0000000000000000e+0\n\t[1\]\t1.6763806343078613e-8\t0.0000000000000000e+0\n\t[2\]\t3.4458935260772705e-8\t0.0000000000000000e+0\n\t[3\]\t9.7066986560821533e-1\t9.7066974639892578e-1\n\t...and 1056 more errors.]
     expected: FAIL
 
-  [X 5.1: Channel 0 expected to be equal to the array [0,0,2.2955899238586426,2.0720272064208984,3.9322750568389893,2.6799845695495605,1.0305213928222656,0.573580801486969,1.1953470706939697,1.1813762187957764,-0.4176445007324219,-2.2066144943237305,-2.9535818099975586,-1.275363564491272,0.26151078939437866,0.6016380786895752...\] but differs in 1024 places:\n\tIndex\tActual\t\t\tExpected\n\t[0\]\t1.7881393432617188e-7\t0.0000000000000000e+0\n\t[1\]\t-1.1920928955078125e-7\t0.0000000000000000e+0\n\t[3\]\t2.0720274448394775e+0\t2.0720272064208984e+0\n\t[4\]\t3.9322748184204102e+0\t3.9322750568389893e+0\n\t...and 1020 more errors.]
+  [X 5.1: Channel 0 expected to be equal to the array [0,0,2.2955899238586426,2.0720272064208984,3.9322750568389893,2.6799845695495605,1.0305213928222656,0.573580801486969,1.1953470706939697,1.1813762187957764,-0.4176445007324219,-2.2066144943237305,-2.9535818099975586,-1.275363564491272,0.26151078939437866,0.6016380786895752...\] but differs in 1030 places:\n\tIndex\tActual\t\t\tExpected\n\t[0\]\t1.1920928955078125e-7\t0.0000000000000000e+0\n\t[1\]\t-1.0430812835693359e-7\t0.0000000000000000e+0\n\t[2\]\t2.2955901622772217e+0\t2.2955899238586426e+0\n\t[4\]\t3.9322748184204102e+0\t3.9322750568389893e+0\n\t...and 1026 more errors.]
     expected: FAIL
 
-  [X 5.1: Channel 1 expected to be equal to the array [0,0,0,2.2955899238586426,2.0720272064208984,3.9322750568389893,2.6799845695495605,1.0305213928222656,0.573580801486969,1.1953470706939697,1.1813762187957764,-0.4176445007324219,-2.2066144943237305,-2.9535818099975586,-1.275363564491272,0.26151078939437866...\] but differs in 1023 places:\n\tIndex\tActual\t\t\tExpected\n\t[0\]\t-8.9406967163085938e-8\t0.0000000000000000e+0\n\t[1\]\t-1.7881393432617188e-7\t0.0000000000000000e+0\n\t[2\]\t-3.7252902984619141e-9\t0.0000000000000000e+0\n\t[5\]\t3.9322748184204102e+0\t3.9322750568389893e+0\n\t...and 1019 more errors.]
+  [X 5.1: Channel 1 expected to be equal to the array [0,0,0,2.2955899238586426,2.0720272064208984,3.9322750568389893,2.6799845695495605,1.0305213928222656,0.573580801486969,1.1953470706939697,1.1813762187957764,-0.4176445007324219,-2.2066144943237305,-2.9535818099975586,-1.275363564491272,0.26151078939437866...\] but differs in 1039 places:\n\tIndex\tActual\t\t\tExpected\n\t[0\]\t2.9802322387695313e-8\t0.0000000000000000e+0\n\t[2\]\t1.1175870895385742e-8\t0.0000000000000000e+0\n\t[3\]\t2.2955901622772217e+0\t2.2955899238586426e+0\n\t[4\]\t2.0720274448394775e+0\t2.0720272064208984e+0\n\t...and 1035 more errors.]
     expected: FAIL