Forum
    • Categories
    • Register
    • Login

    Phase Correlation Meter

    Scheduled Pinned Locked Moved Scripting
    14 Posts 4 Posters 238 Views
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • U
      udalilprofile @resonant
      last edited by

      @resonant Hello. Somewhere on the forum there is an algorithm you are interested in.)

      resonantR 1 Reply Last reply Reply Quote 0
      • resonantR
        resonant @udalilprofile
        last edited by

        @udalilprofile I think this is what you are referring to: https://forum.hise.audio/topic/10913/correlation/5?_=1765392189920

        U dannytaurusD 2 Replies Last reply Reply Quote 0
        • U
          udalilprofile @resonant
          last edited by

          @resonantNo) Someone from the user created a meter from the panel

          1 Reply Last reply Reply Quote 1
          • dannytaurusD
            dannytaurus @resonant
            last edited by

            @resonant There's a phase correlation meter in the HISE master output panel.

            The HISE source might give you some clues.

            CleanShot 2025-12-29 at 10.44.03@2x.png

            Meat Beats: https://meatbeats.com
            Klippr Video: https://klippr.video

            1 Reply Last reply Reply Quote 2
            • resonantR
              resonant
              last edited by

              I'm trying to create a Correlation Meter using the method below. However, the meter gets stuck at +1 even if the signal is mono.

              I'm getting the gain levels using getCurrentLevel Where do you think the mistake is?

              L*R / sqrt(L² * R²)
              
              HiseSnippet 1764.3oc6Y8zaaTDEe2DugD2+nVTQkCHzpJN3TUkl0IosnJjciSRSDNMV1gT3TY7tiiG55cbmc1TRPEwQ9JzaHwM9D.mnW4FRbfKbnHNgDH0KbFdyLq8NqyFW2PZgT08Pj22adu4898dy68lM0XTWbXHkYXleyc6hMLOoUicC3sqzFQBLVaICySasNJjiY1JRKtaWTXH1yvzb7aJHXNUNC4ySJsHxGE3hSHYXrEk3hqR5P3ITqU98I99qf7vaR5ns54KulKMnB0mFA1y3VyZzE4dWz13agDKaLKiUQgsMLunkq27ty6dkly6fPstpSyqfadMmq5ful6BduqqKxcgltNyMGxvbhk8HbJqAGwwgFl4Vj5sai1z6Gn1fsHgjl9XwKNFMfcVQdEpumvEE+1nRahuWsd.UnggoUsDXabErcNq0Idj9zSfuyHYXmHgN.ZNVZya7TlmyAYdYXRlZlTNkIcVqFtLRWdBGg8bBq0BfnYKDDmzME0ZMF6axYUgBqHfOSGzcwqvfW5KQghyN6krKVb1oudd34xW1tBkwv9HNgFXuNFVVdHDFxs2AAILLlujl86Y2Smai4Unc5RCfWJbg9q3BfBSDbiHd2HtH6BjTlNJja4VsvtfPIbERM39wE61xAaSBvy3xv.tJRxXaz7SDBKDHdYyDh4RVUP99MgDsBshBbENRgoy+YSkeJgJqBJKY+jVeD3vA7p3cv9E3rHLnR4RqO7k1B4GJWqZ0tfQrkOHR0KV29x1EVGANY38X79+pP0osunc+2pO8zJoAjLj5imoKi.PnROwb5glBWaKjeDNgc9GH9CDvfTMF2l2FayENu88I711e9bKr5dyjfLh0HwlBysfJT26IAsaP5z0GK7UmrhRZrSGba.FHldfoDJ1BQHA9PPztWTwlFn3IjiQ8K31SnKA5EbVHpkeJssUfB2fyYjlQbbAcF2l3waeIamYE4wO354GtkHzS7d1OUY.aQhQIt35zfC1AELy18DbNxbtg5ZJaHaGSyJTgdMK7VTNdC44CHe6A4sGjUqVYxKVc9P9TVrUYZCQvBAQcZhY5PgXgPktzkOmXzJe5pvDsERCVKfv2nKN98j5+NYTr0HFTgxtiGagvu3xhtmNtnaCehGlYP7DUb6evzP5.5sLMNHErXDmSCjJXBKQLomrVlRQGA4lzRkjlwt9AqsDhiD8Mh8Ev+5hYbh.FMWBuCz0V0EYJqkvg2kS6Jc13LHvlFI28SS1zaTdW8N8cRM4v22g344iqQCIhHu9.DFZap0SChR1uunh198nVkYHOB8lLZT2dQ0QQs8QvCRwn8q382HFFAf5EAMISOWf33ZLCgOq2LVzvM.vhc0CZCNrPtCNae1LmkIyb4QzbOqUMB2sc116XYXuPt0ya6MdzqSYo54jXr4rV4COryYM6nOm0j8mXte4W41eRqj4.Fx7xFFKASNkBxj0tSH7QkyXh50B1ANnVi5iXCB3ieTMMYtQNqPNj1wlr3W2RB4GmLXYJwwGC9LV0P+eHgnNMhSB1FFelQfh2V2JpSC3ZktXvTCBv9ghFoiIZunde1dMVafC7ju72vSLSGw6lwLc5wTGRNuBRNg0sQ6fkyBKQi2P9dKJqi8MwAXl.qbFRIgebTuBc2Q9Jza3xASXSFJHrKMD6nq4F3NjMglfgonNfDE038n9RTLccLdTPZUqHkZUBnXE.JzV2jk6QrnNQHEJkxf2Soo0IZCV73RKGffDjFXvy81HzE.FANqmiUKBt7k7jjitfIjKpSdUDyChgtCq1ZtQq1Z5d7ZqOihtS775qJLh15QUAf+sy0bzzbdpd1np47xPWSeXD29sAZgh748nl9LoXTxtsoAjTY.0wPojs2FmJwJSGBtWFbUpDJmqbcrOFEpcN8cJWEt7GhA3D9PhEO6ePnLiWuokxbsEERre4XdzwOtMO5y7IzLC4iu+z+SGm9WGCCM1L9.phjshV5T+5TZmFj85kS9we6a+mkVB0oKzJMlT44l62Jcar5qZES6qd3C+gRKw1c.Z+dI84YK+q68GkVggw6g0x5gk8ckNxFb8Eca+SnP4WSMVoDdmT86zvpjj3.VUbKst3uU49LpS1tMWujwJXrm3KxnKwO+0OtTO55B7n+pvuTpJ890fMDP360WOe4OUdUx9nZrT4A5ftIFtLb5VdO43aT4ftW1ozH37pKl8pKl8pKl8R+EyFNj.kAO9DAOuEb4lh1x4dr+uevmWDAxWD6QGjKidGW0mSWTicRIEvuCj+ammxZcw61NC9YzML5.2A6NttoU09Dr3gUv4NrBN+gUvENrBdkCqfW8vJ30d5BJth7Mh3zNpyIFFqWaY4+1CSS0mLPdjw3efQSF.Z
              
              dannytaurusD 2 Replies Last reply Reply Quote 0
              • dannytaurusD
                dannytaurus @resonant
                last edited by dannytaurus

                @resonant Looks like the correct formula for correlation is:

                1.0 - (abs(left - right) / max(abs(left), abs(right)))
                

                From the HISE source StereoInfo::calculate function:

                void MainTopBar::ClickablePeakMeter::PopupComponent::StereoInfo::calculate(float left, float right)
                {
                	auto normGain = hmath::max(hmath::abs(left), hmath::abs(right));
                
                	if(normGain > smoothedGain)
                		smoothedGain = normGain;
                	else
                		smoothedGain *= coeff;
                
                	if(normGain > 0.0f)
                	{
                		auto thisPan = hmath::abs(left) * -1.0f + hmath::abs(right);
                		thisPan /= normGain;
                		auto thisCorellation = 1.0 - (hmath::abs(left - right) / normGain);
                
                		auto idx = jlimit(0, 100, roundToInt(101.0f * (thisPan * 0.5f + 0.5f)));
                
                		panPos[0][idx] += normGain;
                
                		smoothedPan = coeff * smoothedPan + (1.0f - coeff) * thisPan;
                
                		smoothedCorrellation += thisCorellation;
                
                		min_c = jmin<float>(min_c, smoothedCorrellation);
                		max_c = jmax<float>(max_c, smoothedCorrellation);
                	}
                }
                

                You would also need to implement some smoothing too.

                Meat Beats: https://meatbeats.com
                Klippr Video: https://klippr.video

                1 Reply Last reply Reply Quote 0
                • dannytaurusD
                  dannytaurus @resonant
                  last edited by

                  @resonant FYI +1 is the correct value for a mono signal.

                  It means there is 100% correlation between the left and right signals, which is the same as saying mono.

                  Meat Beats: https://meatbeats.com
                  Klippr Video: https://klippr.video

                  resonantR 1 Reply Last reply Reply Quote 2
                  • resonantR
                    resonant @dannytaurus
                    last edited by

                    @dannytaurus Thank you for the idea.

                    Even if I don't use the Smoothed function for now and only use the formula, there's still an issue.

                    While HISE's own master analyzer correlation meter occasionally shows values ​​less than 0, this correlation meter never shows values ​​less than 0.

                    Also even when the signal ends, it remains stuck at positive values ​​again.

                    HiseSnippet 1752.3oc6Y8zaaTDEe23rkD2+nVTQkCbXUEGbPkTuNIsEUgrabRZiHowxNjBmZGu633gt6LlcmMsInh3BRbiy8FeMfKTgDG3FH9B.BIjPvg9Mn7lYV6cVGaWSnjlhpOT048l2adueu27duYSsPlKNJhEZXleyc6fMLOgUico71UaiHTiUWxv7TVqih33PaEoE2sCJJB6YXZl65BBlSOog72iKuHxGQcwojLL1hQbwqQBH7Tp0p7dDe+UPd3MIAZ6d9Jq5xnUY9rXvdxYUznCx8tnsw2DI11DVF2.E01v7srb8l2cd2K0bdGDp0kcZdIbyq3bYG7UbWv6cbcQtKzz0Yt4PFlGaYOBmE1fi33HCyIWj4sai1r6QUGvVjHRSerXgiQC3jUjWg46IbQAUipsI9d05BTQFFlV0RgsbJX6rVqS7H8nmBemVxvNUBc.zbhrlWtLlmit4UTy7FfIYpYRSpLoyX0vMjzgmxQXOG2ZUJDMagf3jton1qwDeyjVUYvNn7YCP2EuRHrnmDEJUr3ErKUp3LWMO76hWztJKLD6i3DF0dcLrs7PHLhauCBRXBC8kzreW6t5baLuJKnCiBKJb9d637fBSEbiXdmXtH6BjTlNJja4VsvtfPobER0+4wEm1xzsIT7rtgX.WEIYgaz7iDBKDHYayFg4RVUQ99MgDsBshotBGovL4+joyOsPkqAJK87jVeL3vT9Z3cv9E3gwXPkxsVezasExORtW0tcAiXKePDmYKZ+11EVGANIpYTg0fU0mw9h1RJAn6qwZlKX2aQ8YlQoM.YiX93Y6DR.HUo2DNcQWgqtExOFmxN+CD+CD.gTuPtMuM1lK.C66Q3ss+z4V3F6MaJRI1iDqJL2BpPe2eoneCRPGerv2cFTTSic1fcCv.wrglhnXKDgP8gfpc2njMip3IjKj4WvsqPW.zK3rPTL+zZGq.EtFmGRZFywEzYbKhGuMjWWTjW+fqlezVhPOImYuTm9rEIFk5hqynC2AELGr6I37Ly4FoqorgA6XZVgJzqYg2jwwaHuu.4aOHuc+rZ0Zf7RTmOjOMH1pLsQHXAZbPSbnNTH1HT4Ka4TqgWNUuZuqBSz1HitJkv2nClNrd.FI.IT5MWhUA+Otrv6oRJ71vm3gCMHdhpt8tLZHMZs1lOwXXJXwXNmQkJ3XVh3PWYsLkhNFxMkkJwbemZYi2e0kPbjn2Qhu.9WGbHmHfNykv6.ctUcRl1ZIbzc4rNRmMIqArowxcue5gdsJ6ltXgJAYld3aCHdd93ZrHhHZqODgg1gZ8zfnzy6yppcdOpUkPjGgc8PVbmL3vXo7d33vTOZXpe+MlgQBXdwPSyryIHttlvP3+5MmEMfo.trqtlelM7v3ZhmwpFg61dv13DCvFgbq+KrwjQtNokp2RpANo0Jevgv7US0aR4dkYkG+IrR6+Oh4jMLVBlXJCLIqQmR3CqLfIoWktCb4rFyGE1OHmar8RmQ6kSN1YBxgyNRms9pVRX9ntQJC8GsMxSaUC87JXWmEyIzsgwdCIPoWqaFGz.ddnKFLOJE6K5xaNgnEgZcwtMGafodxEOA9kvzQr1LgoSWl5vv4TvvwstEZGrbFVIB7Zx0sXgA1WGSwgB7wYDWw+ww8ovcF6mBugKGLgMCQznNrHritlafCHaBsvhxPsOIJow6Q8jnT15R7XZVUqHkYWBnXE.Jz12TU5RrjNQHsIixf0Yzz5DsgC9kxKSQPRQCL34daD4B.i.m0yqpECOhRdiwQWvTxkzIeCTnGDCcGUsxIGuZkOkOHvwNx8AAdAXriL8TmtqMp5otLzryGlFsWk7VnXedWpYu5Il5qSaFkjIPWGCUL1dabl7mA5PvylfW5jR4rUpi8wnHsqiuYk0f2lgBAbBe.wBm+we+lAFudcKk4ZKpWX+h63h49+83h41ep8oRRsqig43Zlb4SQxVQKaZccFKnAYut4a2oUqeu7RnfNP2vDRUlateq7svpOvTBsu5gO7GJuT3t8Q6OJqOhYkecu+p7JgX7dXsLZXaec4mYyRdX2493JT9UTS8Ig2oT++rvpjj3xyZ3VZMheiJ8XTmrcatd4fUvXOwGCQSB6O+O+oxcoqKvc9xu66KuF6d0fCDP3Otmd9hetxMH6ipwRU5qI3lX30nY6Z83WbiJC6oRmTify+p2JQd4akd4akd4akdNb2dzv.TV6ncj5bVvaLJYKmQw94yPJGFArCiyH.4Fxtsq5qQKpMNkjB32T4e41osVWr11o+uBsgQ.7Vna65lUU6SvRGTAm6fJ37GTAW3fJ3kNnBd4CpfW4oKn3opWKlyBT2MfmrWaY4e0.SS0q0kWSL9afCFdsF
                    
                    dannytaurusD 1 Reply Last reply Reply Quote 0
                    • dannytaurusD
                      dannytaurus @resonant
                      last edited by

                      @resonant Here's a solution using ScriptFX processBlock() (no nodes) and a global cable. It's a mashup of Claude code and my own, and it works quite nicely.

                      Just put a knob in the UI called knbCorrelation with range -1.0 to +1.0, or use the snippet below.

                      // Interface inInit()
                      
                      const rm = Engine.getGlobalRoutingManager();
                      const corrCable = rm.getCable("correlation");
                      const knbCorrelation = Content.getComponent("knbCorrelation");
                      
                      corrCable.registerCallback(function(vNorm)
                      {
                          Console.print(vNorm);
                          knbCorrelation.setValueNormalized(vNorm);
                      
                      }, AsyncNotification);
                      
                      
                      // ScriptFX 1 onInit()
                      const var rm = Engine.getGlobalRoutingManager();
                      const var corrCable = rm.getCable("correlation");
                      corrCable.setRange(-1.0, 1.0);
                      
                      reg correlationSum = 0.0;
                      reg sampleCount = 0;
                      reg smoothedCorrelation = 1;
                      reg prevSmoothedCorrelation = smoothedCorrelation;
                      
                      // ScriptFX processBlock()
                      function processBlock(channels)
                      {
                      	var left = channels[0];
                          var right = channels[1];
                          var numSamples = left.length;
                          
                          correlationSum = 0.0;
                          sampleCount = 0;
                          
                          // Process each sample pair
                          for (var i = 0; i < numSamples; i++)
                          {
                              var leftSample = left[i];
                              var rightSample = right[i];
                              
                              var normGain = Math.max(Math.abs(leftSample), Math.abs(rightSample));
                              
                              if (normGain > 0.0)
                              {
                                  var thisCorrelation = 1.0 - (Math.abs(leftSample - rightSample) / normGain);
                                  correlationSum += thisCorrelation;
                                  sampleCount++;
                              }
                          }
                          
                          // Average correlation for this block
                          if (sampleCount > 0)
                          {
                              var avgCorrelation = correlationSum / sampleCount;
                              
                              // Apply smoothing (same as backend: 0.8 * previous + 0.2 * current)
                              smoothedCorrelation = 0.8 * prevSmoothedCorrelation + 0.2 * avgCorrelation;
                              prevSmoothedCorrelation = smoothedCorrelation;
                              
                              corrCable.setValue(smoothedCorrelation);
                          }
                      }
                      
                      HiseSnippet 1650.3oc2X0sTaaDEVBPYJNoYZ5jNs8NML8BQf.VDBgVZZLXfDlFCdvz7yjoSl0qVasCR6pQZsab6vyPeE5aRyiPeDx08p9Fzd1URVq.kTvSaZR8EF1yO64aO+sm0si4XRRBO1vr1QihHFlWwpyHlvuoOhxL1aaCyqZ0BkHHw1oj1ZTDJIg3YXZN88kDLmcFC0m+3dagBPLLofjgwi3TL4gzPpnfZ6FeKMHXWjG4HZnlzq1XOLm0jGvG.3YZq5FQH7wn9j8QRwlxx3AnDeCyaXg8VEuJdstq5hP8tia20HcW28Ntj0w216KwXD91cwt25VHCyKsiGUvi6HPBRhg4Law8F0wm+CrTC7HZBsa.Qtv0nCX4Tx6xC7jGQIUil9z.u14NpDCCSq1EtsoScaW2pE0iNldg66iTLrKzP2AZNUY3McI34pCu5ZvqBHYpAoYRgz0r5fioQhBNR7bYq8XPzrGBhS5PIUVio9cSqlbPBlXoPzwjcigEi0vYs50WzF9Z9MpUChUIB63P66ZuCqOkQVpOQb+.dWTvg7ABJqeKDChdwNfzoBi4wwMQvIBzINTJuZkybRFj.jfxYyMV5iYcaVPGTIGXR83gQbFrvYtxhMWJzxryRwj9TY1aSTPPWHaxo2.FVJmyv84wgyW6mpYCefcNgChGESgsLk0FJNk28kRHhGgBFPjRfBn+Hwarz0NYQ6MSFwv6yEzdTrRAfdtEs4LfC4.lizpyV6jZ1mlUudUxSdti4AARWYErkUQwuIEcXCB6RhWzdnD5iEDxTJm9Y85S+zqNvogAMA4r8XTwAQD1qqlwHK1ISUyPEHpPknd0rD0NATORrA0SV0T1uanPtdiEiuausQBT99AaMXtHRrfJOIlaSFBMdRKDl0ZaRxwBdjR1r7Fn0v425uXrk+kdMFMdwq50HrTGveMj54EPZySnJ8zw6YKPgVCbuAfIJ2uP1UMigbOzKRkEhLXuGo208erlHmWHdMq1TA1uZLNUEXDBR+afwrVuen0N85QvhB.Ni0tO4sWe1ZYIPfMkF+JYKs28ItU1g8msrR6uMDEewZeJU372BMuEHzx5PDqOw4ltKAcugujMqfFi1ZpzYfDH0Wp9FJNInvn.RS9.lPRNiXHmK7IdkaJ6lxLJlLrSkBTgZaLtGEnVDJlbDuc.ZjSpYODBRKZ2MfiOtCzg8rM1hRiAaIkvA6iXLRPhRLoGJfzSB5b5Oq92m1IW4to88KwzUiIzkriB.IfDxcYo.BquvOUB0WU6wjbNiGarNKub9s+1DD1OSR6HDMVwuGO11QZepRQ3OesFTf0Krv7JASupJGsR.lJSFZeFM6rT5vNVD0pRxTRXFbIlryCHYKjvGt7+ENp+A0MwovVyun8XpZ6+7yWw1R6Y6Lda+FoqZ9w7JNK4.P3SSNUl0R0suocUn.Hqab6kGCeMbTQ7Zg6dZyTVbsf3BKTv5jZEemGR2bHIFpN0sfJRJ2+zb2Z49.8TCvMTUvDMre4y9o.9x5PqBWsDPQQAixJ1flGJyRrQ.XfwdHLuuBB.qaeCUgJkOHwdAfvJ.A7.vTLQQro557BsqpLOeyJePJP5Eq8vYOfkZmol.yoBEyh9mbAGCx5be6f6a9xowMtEwTXlAq8gxX3wLXRyr9M.MyojSCktttbs79wNP.Rs3OgOYLckqMyX5lyrXPpIZBH86O+7TlW15wngD0q9TWf8Ip0Ptbn88ILHKGbMtug288am228Ecte22AXA.gihQrjHdBwUameYGRH8HXDtDcpmViUpTCcpFaSDCX5a8pMRIURJoqXWvU3pOwUNwUzI1FwzD5ouDVqw+oMZQKlhz3U2aGlLatCAN4dGjfAGizOWZCGDjPdL0S36pqXA4UzI+.TrGDCw5fGRniEs8Qk8fZjKcTMm9M8VY2I7sxW5ct2J+dvj3kFyb1bL1gJuBXG1PR.Tmqv3GCE18PCBD4TKWn1hy3Q9bFsTZwgDn8TeXxRcrW4AZSg.t7nfx0abHIf.INEj9hFODlcEEC9IxD5KbuvibWY75yrRgqsr6h86uufZ5+W+Bpye0Gzv7c6n3mZAMtWwVEJs+uIV91Xfi2F1HDgi4OGmNmlrn+CTTfyMS8a+NqUK4Za2y9CAEBWY7bLt7VcFEWYRU7VSphqNoJd6IUw0lTEuyjp35+8JJuQeyABdXZsggQq16nFa0zLcDHUYhweQsTysb
                      

                      Meat Beats: https://meatbeats.com
                      Klippr Video: https://klippr.video

                      dannytaurusD resonantR 2 Replies Last reply Reply Quote 1
                      • dannytaurusD
                        dannytaurus @dannytaurus
                        last edited by dannytaurus

                        Note that the above code spams the UI quite a lot with new correlation values.

                        You would probably add some throttling with a UI timer and/or on the processBlock end.

                        Meat Beats: https://meatbeats.com
                        Klippr Video: https://klippr.video

                        1 Reply Last reply Reply Quote 1
                        • resonantR
                          resonant @dannytaurus
                          last edited by

                          @dannytaurus Thank you su much for this useful tip, it is so sweet! That is exactly what a correlation meter do.

                          Do you think using Claude with Hise is useful? Are you using the paid plan?

                          dannytaurusD 1 Reply Last reply Reply Quote 0
                          • dannytaurusD
                            dannytaurus @resonant
                            last edited by

                            @resonant I find Claude very useful when coding. I use it every day in the Cursor IDE when I'm building web applications in Ruby on Rails. I'm about 5-10x more productive with Claude.

                            I'm on the $20/mo plan with additional OnDemand pricing for extra requests. Given that I use it every single day, often for hours at a time, $20/mo is a bargain.

                            If you open the HISE source in Cursor, you can ask Claude questions about code locations/definitions, workflows, how to write scripts in HISE, etc.

                            Meat Beats: https://meatbeats.com
                            Klippr Video: https://klippr.video

                            1 Reply Last reply Reply Quote 0
                            • First post
                              Last post

                            30

                            Online

                            2.1k

                            Users

                            13.1k

                            Topics

                            113.9k

                            Posts