HISE Logo Forum
    • Categories
    • Register
    • Login
    1. HISE
    2. HISEnberg
    • Profile
    • Following 0
    • Followers 3
    • Topics 51
    • Posts 571
    • Groups 1

    HISEnberg

    @HISEnberg

    232
    Reputation
    183
    Profile views
    571
    Posts
    3
    Followers
    0
    Following
    Joined
    Last Online
    Location Canada

    HISEnberg Unfollow Follow
    Beta Testers

    Best posts made by HISEnberg

    • Free Reverse Delay built in RNBO

      I know some users were asking about a reverse delay so I wanted to share one I implemented in RNBO quite a while back.

      Link:
      RNBO Reverse Delay

      Unfortunatley I am away from my Mac at the moment, but I will update this link when I can. If you can't wait there is also build instructions for Mac.

      This project contains three folders:

      1. RnboExport: This is the .cpp .h files created by RNBO when exporting the patch. You will want to drag these into: YourProject/DspNetworks/ThirdPart/src
      2. ReverseDelay: This is a HISE project. If you are on Windows, after downloading you can go straight ahead and open this project. You will see the reverse delay embedded in a scriptnode network.
      3. RevDel3.maxpat: This is the Rnbo project itself which you can open inside of MSP/RNBO.

      Once you open the project and the Scriptnode there is a little write up about the reverse delay (just make sure to click on the comment box next to the xfader to see it).
      dc1d3ea7-7801-4355-8210-3761829f2582-image.png

      Most of the guts of the patch was taken from this generous homie, so shout out to Taylor Brooks for sharing this on Youtube:
      https://www.youtube.com/watch?v=hOX5eg7QCqM

      I recommend watching it and following along if you want to know how the patch works. My patch essentially operates the same but I added processing to make the left and right channels function independently, added a feedback path, and I also tweaked it to create different windowing functions (triangle, Blackmann, Hann, I can't remember the others). You can also tempo sync it in HISE using the tempo sync node, it's easier then trying to do it in RNBO and communicating that to HISE, then to the DAW.

      If you are on Mac, you can build it your own. I am not sure if you need a Max MSP license, but I know you DONT need a RNBO license. You will have to install Max MSP though. A RNBO license will allow you to make changes and save the patch, but I am pretty confident you can open and export patches without a license.

      All you will need to do is open the RevDel3.maxpat, then follow the steps to export it to a HISE project (I recommend this video):

      Hopefully everything is in working order, its been quite some time that I have looked at this project. Let me know if anyone has questions or recommendations, and happy holidays!

      Hisenberg

      @DabDab @udalilprofile @treynterrio

      posted in Blog Entries
      HISEnbergH
      HISEnberg
    • RE: Reverse Delay Faust

      @DabDab Cool I didn't know there would be so much interest. I will upload it on the forum in a couple of days!

      posted in ScriptNode
      HISEnbergH
      HISEnberg
    • RE: HISE Meet Up

      @ustk Only one shirt will do, hopefully @Lindon has some spares.....

      0d94aa62-654e-4c49-9983-0beb3117ff3e-image.png

      posted in General Questions
      HISEnbergH
      HISEnberg
    • RE: ChatGPT HISE Copilot?

      @hisefilo

      Ah I have been unmasked.

      So I have been working on this since the beginning of the year. I simply fed it a lot of information from the HISE docs and this forum, forgot I had it published. If anyone has a problem with it being there I can take it down fyi. Just send me a message.

      I meant to share it here once its performance is optimized, so the fact that I haven't tells you all you need to know. I also figured theres a bunch of users here who probably have their own versions (come on guys, fess up) so it didn't seem worthwhile publishing in the forum.

      My opinion is that it doesn't understand HISE scripting even until this day. It confuses HISE for Javascript constantly. Even after months of training it doesn't grasp simple concepts like the inline function and ControlCallback. (I don't know how many times I have tried to get the GPT to understand this but it constantly gaslights me on it).

      What I find it good for is mainly debugging or writing out redundant tasks. It seems to be okay with LAF as well but that is about the extent of its capabilities.

      As @d-healey said, beginners should definitely stay away from asking it to produce code. It will very easily provide wrong answers and tell you why it is right, so it can lead you in the wrong direction.

      However, if there is code from the forum or docs that you find, something about the ScriptingAPI you can't understand, the GPT is actually quite helpful at explaining it. This is where it performs most optimally, and it is also helpful for checking your code against (but always take its advice with a handful of salt).

      In short it is good for speeding up workflow and checking for errors, but anything more than that is asking too much generally. Its also advisable to know something of the topic you are talking about in order to prompt it with the right type of inquiries.

      In any case hope you all can make use of it and if there are any issues people see vis a vis intellectual property, reach out to me and we can talk about it

      posted in General Questions
      HISEnbergH
      HISEnberg
    • RE: Cost Of Operations?: License Fees?

      @HISEnberg said in Cost Of Operations?: License Fees?:

      You'll also need an Apple developer account which is about £99. And if you want to codesign on Windows you need to buy into the license cartel, although I think @aaronventure found a cheaper solution.

      Apologies that was lacking context, I was referring to the Windows codesigning!

      Just throwing this in the mix as it seems to be a relatively recent article with up-to-date info on codesigning for AU/VST3/AAX on Windows (Azure) and Mac, as well as the fees associated:

      Link Preview Image
      Code signing audio plugins in 2025, a round-up

      One of the last pain points before launching an audio plugin business is dealing with code signing. The ecosystem has changed over the years, especially on Windows, so here's a 2025 roundup.

      favicon

      (moonbase.sh)

      posted in General Questions
      HISEnbergH
      HISEnberg
    • Free LED - Activity Indicator

      Just wanted to share an LED Indicator I put together today. It comes curtesy of a script that I believe @clevername27 has posted before on a VU Meter (can't find the link) as well as @d-healey 's video on LED styled buttons

      For this one I just mapped it to a gain node but it could easily be routed to something else.

      Led2.PNG Led1.PNG

      Enjoy and let me know if you have feedback.

      HiseSnippet 2181.3oc2Y01TajbDdEv5Xzcj5tTWpKebJW4CqHJXsB33HTjCYIAnJ.RkjNewkKJpgcGIMm22pcmErxU9eZ9P9Ij+AN8Ly9xrn0XLmOebYKaX2d5tmddlt6o6gAg9VjnH+PsJUGOOfnU4y0GM2iMq8LL0SqWGsJ55NDasmMO.GEAuToxxGwGpxpqnId9ue2yvNXOKRNIMsm6SsHmPcorbpCN3ePcbNDaSFScU3dqC5Y46012wOFLik0anEfsdEdJ4LLmskz0NFGMSqx556t81lX6I6LwbSycuzdhEYycZ7MasSS71e6jI6zvbqMs2YxVfQ9nt1Tle3HFlQhzprxy7smOZl+0dxI34zH5kND9GlZifYVR9PeGa9RjSUq8Lpi8fT7IRCPhA4n0xRz5qzOkZSynmiZegX.TtDp.XkkJZdKWv7LUMuFJlWIlTEESZEoI8k5irBoAr7Q31ymo2yiQBmfg8IUSQxq1R6uldaefCO1Ft3WQNLD9HSBCyFMpifeTaupUe5SQ6m8fNoaGTqy5cZqw85elx.b1FOiFgf+4hCBH1HlOhMifNEGApEwchPt91wNj5nKiYHJCY4G6Xi9w3HFBGgH3HpybthtjfBIAwgA9QR8.ZDg8li7AEFhlD6Ywn9dHCg9v72qiNsWmdHxUvJpNhvr1n1Zbam65EVE72f43JbHhg1G00aJ0irgUHA1NDLz+xejXwLfk6ZJ7NvyokG0UnePrT7ZJg012Mv2C9v3IpL8jZ6oJOeImr52GIhx3x1cxD9b8D4HbdDhkJXmtsa8hKF1ZbWPnFar6dH.P5PrvyQCAyMksQm1u+3i6c1QWbXq1i6ODX1D8WAA1YagDGReM.cQt9.jQ8lB1iSblvG+hQi6Nr6nditX7wvuOt+IcDyVCEYmMmaejHXCUHb5DOnaWNylaCbyMaPf1wgg.XfdNmun0pFRlhrhCOA1MbNIQwEoNr.UoYRrKQfBCkKkXZOAPPzQeeOo8Egl3GpX0qUkuG3.7bTLUXY4Z9libCE2gLAbPPrq8AWTGHxSnZJO7HvW5ukBkN9Wyyjw2gU8D3azFOgxHtx7bJdFynSmcWDoYhaA0ygaLYN84lAQnFCvDpKzZcDD7BoYpg9o0phfGGeKrSBQX1NECdfgXuoDCIs57EMDnuQC9TwkHjvhC8PRKHZCW5qKQ8.uuIam+RpUQjIyRWzzs3b2SkYiHFNjGv5Y+wy5E5D8WPFfVgXBwm0PqiRjCdK6EiMAFZlQol5Za.1i3fxy.Xz0wgFDQPWSYyP1y8vtvZW3fTDAfLOE1XiHrAPXNaneLCvCiT7vXZ1Zk6PhgEIDrFwcDNgu1elermcjQ1xiyjmenK1g9uH1hDpEfkhwJKBOb4sjgpoNfk4LIdodteZ8aLoR2RtB4wfPx.YFs+FpeLOU2zPrMkmMHZF11+ZQnCmqofpQDAqRomxAliR39PnTAiWl52wQ3VNAyvFYTlAQF7kz10pivur44nmhZxeaS4aRUVxy6VkW5.kcvUYSgJabN3xHz75.sM2YaNQSIwMUHxBiImmBoS2XBX3INFFu7lZoQIJQRKggcqmOvtmW.Y644QxQtO.HScKVt+WDwLO+CAsJpsFar0B3+cELLaVBZjPLgEInuY5GEAj1DtypvuzA9+OKuns9YgIKnNyaCTrCwW+wDTpiZJioeC+GUYb.PTESariykfOcdBFH+RVjOOz8DxDdAP4ElHJlQtCKxZXXVaODpfLC4X8sKjnNwTYBH3WkcPd5jppzLFFlvfXFRz.cBxPQC+875HRWK7G0hKx4dOw3uAQbfjzkw756qTdUB2het3TOTYpGV1TOTcpG9dl5gkO0od1sBBblKOc7FmklU.mf0EpSprCTKvS87Ue8EpYr1dKp0g2AsNLWqCKUqB0V3HPnbd9IfPE1HtaqnqhQDlnAAlnDcvMleNsvQ1PTjYs8xJbv26LeFoO3PW8mptZUXS6lCMYRoiwqYOz2wAzYYCKmsaQPCuX2KIPhOQIlYLBMeUriN82cGcpMbZIagPgQeuddTV+.h26pMTsj9Nf299dcvLLuMvDZ.eAjPFkaBU5PtBZBW1T3p5cHQuh4GH3MoYEsJ+NlXz0RaYjWgiFEZL72qqtco8Z0d6mq9wLBOXMmxKNPohUf7id6+V6s7AxIyo1XcIUsE6eE5bV1EWw1oEoaxZuqPOrbWSuHJat5kR7QqG66pI9k5CnLqYkaiKUhMB6a+RXiI2LwZ5xxvxMvUzO7e9I3ZHdb18HQcCbHGkN8etddGt2x0Ioo0g3fK.S+.0lMS0EqjKbpm2Ufi+.H+T3MA4kuyqRyaeUtxc1SPTK9CZu0+ft.lenajhs9G1F4WnCoM+UxDkcPNE54KjB4n0OK1cDjg0h.lGztfC+jnJKwOyP9cC92biXDzJr3i2BOICZx+tRxfloCpBCesDF9L8e.eEQbAVBD3OJ9F5qyEcDAZRgiOleLtw3f67MF22hAlvXnu2H9kDZpp4QDW5X3.unBTugDMKUhlEyKwh8JpZIoBbwghCAnPguGePJwlpDA2lBJC9tflNkpbr6+4655gAmhQDXka2OxB.FNNqhpChgpMEQLlpBlStoJ4iwg1vdn0skqbk6Vtx2y8l+nGb2a9uAJ6nvYpqlZixyT6BG14.U5kkIeBN1gkRsXn2o9d9Ay78nE1nGRfLFSmRJ3+T5BpEiAsPlS4qNXHwgfiTBG+yGbB0ifCAbhbOwByO3+LGkte8mzklKhmu.8a2xEW9+qKW7tG8Ao.eXuK905Pp3lHwVI5Wm8xOE0.7oXNbwVg9WXI6ylGz+XAEXc6I96.uJz+.7MxTSz6sJX5BGYbgkUQUsffMuuBt48UvstuBt88Uvu49J3N2WA+12uf7SzaEy7StLAnxlAcEWbQkJxhZDgIZ+OvkIPQf
      
      // ========== LED ANIMATION ==========
      // This is mapped to the Master Gain module, but it could just as easily
      // be repurposed to map any other function (modulation, MIDI event, etc.)
      
      //Timer
      const var t = Engine.createTimerObject();
      
      const var PnlAnimation = Content.getComponent("PnlAnimation");
      const var GainMaster = Synth.getEffect("MasterGain");
      
      const DECAY_RATE = 0.9; // Decay Rate
      const SMOOTHING_FACTOR = 1 - 0.75; // Fixed smoothing value
      const HYSTERESIS_THRESHOLD = 0.0; // Fixed hysteresis value
      const SPEED = 15.0;
      
      // Current Values
      reg curLevelL = 0.0;
      reg curLevelR = 0.0;
      reg smoothedLevelL = 0.0;
      reg smoothedLevelR = 0.0;
      
      // Last GUI values for hysteresis
      var lastGuiValueL = 0.0;
      var lastGuiValueR = 0.0;
      
      // Define two colors for interpolation
      const lowColor = PnlAnimation.get("itemColour");
      const highColor = PnlAnimation.get("itemColour2");
      
      inline function interpolateColor(low, high, factor) {
          local factor = Math.range(factor, 0.0, 1.0);
          return Colours.mix(low, high, factor);
      }
      
      // Cubic interpolation function
      inline function cubicInterpolation(start, end, factor) {
          local factor = Math.range(factor, 0.0, 1.0);
          return start + (end - start) * (factor * factor * (3 - 2 * factor));
      }
      
      // Panel Animation (Ellipse with dynamic color interpolation)
      PnlAnimation.setPaintRoutine(function(g) {
          var a = this.getLocalBounds(0);
          var normalizedGain = Math.range(smoothedLevelR, 0.0, 1.0);
          var currentColor = interpolateColor(lowColor, highColor, normalizedGain);
      
          // LED Effect: Outer gradient shadow for LED glow effect
          g.setGradientFill([Colours.withAlpha(Colours.white, 0.5), a[2] / 2, a[3] / 2,
                             Colours.withAlpha(Colours.black, 0.2), a[0] + a[2] * 0.375, a[1] + a[3] * 0.375, true]);
          g.fillEllipse([a[0] + a[2] * 0.05, a[1] + a[3] * 0.05, a[2] * 0.9, a[3] * 0.9]);
      
          // Inner LED glow
          g.setGradientFill([Colours.withAlpha(currentColor, 1.0), a[2] / 2, a[1],
                             Colours.withAlpha(currentColor, 0.4), a[2] / 2, a[3]]);
          g.fillEllipse([a[0] + a[2] * 0.125, a[1] + a[3] * 0.125, a[2] * 0.75, a[3] * 0.75]);
      
          // Center highlight
          g.setGradientFill([Colours.withAlpha(Colours.white, 0.4), a[2] / 2, a[1],
                             Colours.withAlpha(Colours.white, 0.1), a[2] / 2, a[3]]);
          g.drawEllipse([a[0] + a[2] * 0.125, a[1] + a[3] * 0.125, a[2] * 0.75, a[3] * 0.75], 2.0);
      });
      
      t.setTimerCallback(function() {
          var GainLeft = GainMaster.getCurrentLevel(1);  
          var GainRight = GainMaster.getCurrentLevel(0);
      
          var peakLevelL = GainLeft;  
          var peakLevelR = GainRight;
      
          if (peakLevelL > curLevelL) {
              curLevelL = peakLevelL;
          } else {
              curLevelL *= DECAY_RATE;
          }
          
          if (peakLevelR > curLevelR) {
              curLevelR = peakLevelR;
          } else {
              curLevelR *= DECAY_RATE;
          }
      
          // Apply cubic interpolation smoothing
          smoothedLevelL = cubicInterpolation(smoothedLevelL, curLevelL, SMOOTHING_FACTOR);
          smoothedLevelR = cubicInterpolation(smoothedLevelR, curLevelR, SMOOTHING_FACTOR);
      
          PnlAnimation.repaint(); 
      });
      
      // Set the timer
      t.startTimer(SPEED);
      
      posted in Presets / Scripts / Ideas panel led animation
      HISEnbergH
      HISEnberg
    • RE: LAF Collection for everyone

      Draggable AHDSR Component

      I've been a bit of a mooch lately so wanted to contribute something myself. I've been revisiting an old script posted here a while ago (can't find the original link) on creating a draggable AHDSR with a panel. I really like this script but always found it was a bit difficult to bring to new projects. I didn't do much other than organize it a bit and make it so you can attach the paint routine and mousecallback to several AHDSRs, and I hardcoded some of the values. Still a work in progress but here's the script:

      *Edit original script, courtesy of @ulrik :
      https://forum.hise.audio/topic/4541/paint-routines-adsr/65

      example.gif

      HiseSnippet 4331.3oc6b0DaabbEdos23P4TmDjl3dbhPa.YLkL2kj5mn3JIqerEhksfoyOFBBIK2cH4ZsbWlcWpehiQywdqmysbpG6kVTfdSnWJPQNjhjC8TQQu0dnHW5019lY1el8OpkTxNxokGj3Nyady68l26MeyOb2x1RE63XYKTXh6eXerPgWPr4gltcWoqhtovFqJT3hhJc0brEtwg8UbbvZBEJb9aRprPwKHP+7sKdCECESUbXQBBumktJ9158zcCKcqkdGcCi0Uzv2WuGG00WZCUKyUrLrF.Bx4EqJzWQcWkN36nPH6bhB2RwoqPg2Tb910letYppTSaNUrpZ81Mlcl5JR0q0PAOes1JRp3YaHqBB4yslltqkcSWEWriPgKbCKsCa10ZeSVG7d5N5sLvjGjDZB8Lq30sLzHpHoTgU5panskuExQ.X5Vg1qyyrW+PwM00zCJOzt8RzJPgsf2.V3bQEuyGQ7j3EupbhWJhTANQ5BLQ5kEapZq22MrFh7bIwMLcw1sUfwIdQgQqv4lsj3JV.EltS2SYW751vCAsnzLUqVAUqQ0xKLwDS.CVNtn8TrQ6Z1x4CWybOz0Q9MtC1cYCiUr502xDd1ozj.QDZlDZaXK6qXhMtos0f9NCsw8MMR1Xr4ddMEAMl5v50zMszFXn.VVnoKS7ai1vcMsZEzoauCnLlfKlC3tgQPufMr5im3QEmn30tFZpT+Pq51KuN58V9dar7Mt8ZMQuAh455LzlEJD2V2D+95ZtceOEiAXpJHOc0EPHdhfPJil5eB1mFfnZIHZcHbZMSEvSQCgXDIs.4+w6tikHR24vSUHQIjJvmUWkoxTBqdv5qOizLUWs1Bwo8VV6gsCHkQ6JqrN8SDhUTc02CynTxWLqdv7M7XLJIwb7VJFmiPstYBlSnVpZHqOtw62AbaPT+FcyNCkXcSCvbiZOvD5SKSDD84BNVDF3Tp7DEezDEIBfgkphAxbPu.mw9J1NXHdqjeH0zFXyNtcQWCMG3BSaUaKaTIchzu.RG81gsGd7pWsLiHudnHqK5Pp2yWuHx+CkQOjwnGBLZN3eAL.wwkvOTFMc+ANcCjvs0QuIZNzUQObmx7b+wbeOLfi0VJa7oFH7wDieTizBG+3wMMrZAJ2VjbHve0McQ2yZfKX4GoAGubKaY6MxPZ6pXHkWOBYLSmtoF9.nJNy4Fjh.i2TRfnVL9fBWhMugP+QGZWPsJ5sQkb6pCi6Wmm9s02orOIAzFZ886W8EhTWKarxtAEAFThQsHoK3aEQbCXtM1cfsIj8yWu1GXKQfHYQoolnCCdU1kqxag06z0sTYzTHoPJ1iiBZBK9la0tsC1EnHRJsv5M7SGBjDM0XHM8UzzfPOfhFgE1xx00p2VAUIWMrNGCKRWVZePPkA2TOFTFBm33vAgeUqEmD25g9gLdkPmkfT1jK65BXSlrBZxaAXEH+eUrpxgjuzbfiK3KR958vFXEG7jbrfD0bWaMrMgMvjoxv7oUP0qfZDgHHD.HHLrY6vAQN55yMmoJL96h2RwePq+zpPmaWxOJi8Whqssx9joNoyxgTGXuG1qx9SCRts6cv62bPKJm7rWUfA+oBr9SEyjOEp5zM76FhmI0p+ln81t5NPZAul4U+daKsC5mB+q9NnE4xPn0hLN0M53T7tpLTUIInTBWJGxazacB3TcdNsfuk3iGnnYSlg69VkN.bWj45sqQF0FIYM76yrSYttqB5fJf.6a7.ONV9wsoEGjO022bYPyndnLK8U4L0x6DH5jHIhTmGNGkI0HBprWUmF1QOAmxJ3OSQzgLLwSwKFf4kQN72fNXVvzkSCFmWX8TFbGeKTicNdwuwNCMdgpB4NdJhXMjVsSz3bZZXMEWkoAFfUcIYSfuEYXQAxXPfbPRWeCqAlZNkjhxkNS2B2Q271JGhsK4ZO.6WcmoaCXNAf1k7y2WZxVcXPqlrbHUPFeVgbzo6h6EmRxzTbnX4gfv5JV1nJTYNurWNJ+4..Gk+vn3977uR3bQom7zsqkCF0hfUNj87PmihACkFnsF7f0RGqkNY55vAxtDftnEin1w.WWF8VIplGmdD7YnPOgVGvbO.jGjb1S4MYcVTeXH0RCgZJW2DLrSaqX1AWpE3AGj2a+f1QR4D5WmTDocGOaNjiMcyfMIxSkfsrw80LLz66fKsMQ3HbNjY7eGhnkSCb6iSy8vPoEfGc+tXSDcLiHNzwNXwHt1VFg9LwGbecO3YwcG7.yLnca8CVHhuaZQ.t3CbiGfER95fPTZRFzYx2AbJRQ0MerV1J8H67BX8o3d1NlztSx1PpLXvhjQoDEIy1AfdRvic3vJFQHhaZfPgZfyOyF.8wjHsaLI3tyUPOmISJRrAiqyoNWEM4aATeUlzd0TMqDWikMz6Xh0tOXMKQ4REJfM5Dhv+2GbIpB9ESpBnurwZ2f5tMY7E0LBqfYSqAPZkUfX1V.1xSxRY1TktTFpmYlqlARf4.qxGZkaWJNPaPQXqCg4YV9Ys06f3mcK80xDVeZKmIBAouZFtvQroCc4FUiTbz0nvk0LskoDl7HLoPJKWKPo8WwVXIgsCuGYY.rnk23MPuN6YvStSlYTTMfIxbHqPRpZ0pSWMY3CjleCsCROvrGwe8CfFy5ogQ0CBn5vj8gqlE55IQrrvIa1SuLR5sa+A9ojTZ4TJXCVfdkMcWY5rFdk5oJkSNeAwDy31a6a2JGmlDBA8SnUl19ERkHlg1yMOZUONdAXCHOQn7.dIil.QZZfAwyNPmHOlY3PXoJuMJBkLwLSxKmZ+cbJXTkxmPXvNOrSZn1qGOroTxx61F2mrYRk3xkGQBectPsThsR1OSIk29Hd3rpgt5tPV5O8SQCMdNQKxQrw6X1hlWyIwFCh7fybS.8CYxA19QPBB4mpflnJcVerafQzFEO7l17XSijGG6.MxeGJIfOzCwXbGK6dJF5eBVqTJQ3IhyBGH2y2NEzCYsSmbe0YecW0tIP4MzQFUXNYT02JyvV1XrSW81tqZsuYnegMYFrUHi8oGz7nrCkRePZ6Y1g.WLtcKtMAHCvPE5a9AWiLuX4EFmtSsKAfuVoLZ8iyLuwojFWMeZb0SIMVJecGMUaX28fws6pdrF3iQXGqgGeXZo3lKktadFBfb9rVxivfS18zwnpCQojycr6oUb5r4yvL6ojW6re2GmVKeZbsSIMt1ouqesQx0ud9z25iPhhr6ow20u9HoTMxmR03jGO2XzUpGOFKhmd5vqv1hmfUwORqd2xb4asZy6AXLb73SIU+6.QED0f3cBkYrr73q1e+t5..D1Z9Ia9Df3zgBgyEfKzgsyTDi1zorfdtirMq0yG+7i4r+.nK+VwNR4zVdOIoXj1r8C2gtZFektbDxi13icCBRYWBB1pfneI1pte8HGRZT1j6yTsX.VvQ.QLizfyl65g2vkLIlseMQ2OkrnUwEF2aMvkg3WtRsJ0qznxLUlsxbUlOE1lwpCB1sykcbz63s8QL+UGNBndG6x7N1kc6B1M90SfMyfm9RxGrruHVJTX2d2cpf71HwL2uPNAlG7+tCG7uWbNswAoiJwwKeBYTvmFIGIF3rOQ1nO+jCPrnEZMEHDkV9PYW92usGwIwgQifxQugDd6pXI+jNkRa0jb2HBeCUDCQD1R21ReUJjuzb1g7tXQt8ljmoilcL0jrDy3xFrLvNHcSlM8lrkmNB1zLS48HNO5bluKtIMddN1N2S0i.aWx7+Q1M4GOwDSvMWwcrbw20rT4IftApCEup1sSsNONafsSsZxUxzdXMrj4fdsv1AyG4QnPgKD8tLJl8cYj+pVpxt9BbDZYtgot6c6iMy5BXJ3cmGDDJ7RdREPpK8VOdYua8XSCcMrsftF4tY5c0CYWZChFJIPkdu6d5W7U1FKIjCN8pQ4zsAebinrZoZ0t3Q4gUW1mUj6ORTdbzq7K+M4RbdEedPu6II0qiJ7aWLWL5k8Yj2cWIl44a9ZoiFI13cuWhwl+laywwJuB4FpDSw9xu7aVTXTF5oVnT3D5Wcy+znwoPmH4PN8u+Ovme1GM1NQbrp+F+8+H9ubkQ2IRNhhIH7y+5wzIJFi9ra+GFKmH4XwX+ywyIJtZc3udrchhIQ8u9+XbchhxoO62+u9yKJ7tarJrtExcw1K8DjxpO11UmjMrvp38zUwralcQwUwN65Z0Wnv4BtjyBElfIA+.+6sMYlVp.bEQxbmqv.vis8ugxBGveS6Oj+g8IG3UPAGYuTW5IbETxRCVx+5Z.8qnzLyN6rxRMDBO5XxOAf5xyWe9YlUd9FBb2pBVMyNmz7UqNWUtZXULmzbyVu9byA8Emt8BYoaSH5gKP5DnNBOXo9Jj8jlqGyxnkpdmP8BTbXtYq8C.rIT3EEIHMBKHGVLVOUu97MpMCYtq.Q7Ri1TVb1me7Rg1mk9nk5YoA744Do+dJ5ob.eN.GWbex0sj+GpQOcMMC7VVN5j41C4zuXI1ggCydKh5wTNxfFSJPtD1maCsPxg+bOkZnFbTqnpJSjtruHQoWfo+jvJU8Vjm4+co7fi3sHvmXVju3y+7e2hb5s1MDxv9HHezXo8WJun.xXD9yZ+DdD94DI8uvorxkF7jLzviLdBqgWTjJDm1duIANkgmKLDxDjhhdj9rqSaRXdY429wOgGUKJ5IBi23ZwQDBZFisfyarrRT58FfeMwvMdXKrM41BozAK3qNmW7mj4H2ecwSY0JU3vY4w9wmszpLQG8iRuwQTL6kdJCOZtpUkaTEPAk.dTcYo4qMu7nBOR9TFdTlVsmUwGIeVEeTlV5wGfj7yP.jxk5eo7tD2yZHjNgZWZK99LGDoSnCbx8E3YBLRmvQ1jaiwYPPR4RGKNh6wxY.TRmP8J0M74L.LorUqj+5+eIwfeC77uLBHuxF7pfza7uA.H+J+MAo3PdWsSs2PA4UDeYwsH2ZtzkwykhLJH7DQF8duN7CDWqcarpan.dAw0+fmLuDG369Ky59KI1DFoouYCnc9qQeF89J6gQ2DC9.DimzPdob7U48kxQ+b+R43tptP2eeaESm9VNQXbSbO86CNqN7E9tN30swe78Hil7kuhE45CmRUe6hqCJYpsooh6.apawx8rFX5FwM37C6c8gzX9t93Bm4dWe7LPvdjWGIuHSFunH8vMoh1yKReobD0wcSKSq9csL0U4ko6g8tqJ7ElpzyMID+wDElCm+HeXDye9ebvq82VexY4Qg8wctbLLRbmulOTEtyJye9Vty8ZMUqMYXYFGqszvs1h4ziHXgJzP7yd49isnkydB3KvfHeV098h93lOyZ.urOVzyplvgB+37e+F9A6pA0YSEHiKYMD2YPulvr9pXn2MMwFjK0QgyQl4l8bUxyro8M0nOPNEbuJkHOWvqRI+J4Uwq3CwgflIDhyqRetM.a9rBBGoTg3DozXsPN0VDozUwtCLixZVQQnhXJVGLEbz87K4WnLegaoXFgYvyQ3zl5Gvu1B1OT8lXPy0tqiJXXH1Y9PusFX3v9QvKw2vvhk4K9VJ1ZvXn5Sd.YO2+GP1SL.YxOgAjQuxEI.jQu9DQ.jAk8Qo.H6Hx8hgCPFcCR3AjQuqJw.jQt2IQAjQuCIee.P1Exm6vvCndZAN6opvdx.p8TUTOwf1dJ6Ebx.v8TUX+eYvb4dNI.X.5L8NBdEQ.fhLhNTh9tYr7oAx3mF8QOEUaqOz+2pAXgddZIfdaReE6VTbSxyHoX24R3SO.H0GppFkUIZn731vZiaCqOtMrw31vYF2FN631v4N9FRv4t7.WqdrXC.u+VqQuNpEJ38NohDlH7espGt3J
      
      Content.makeFrontInterface(600, 350);
      
      
      const var knbs_Env = Content.getAllComponents("knb_Env");
      const var panelGroups = Content.getAllComponents("pnl_Env");
      const var envGroups   = Synth.getAllModulators("Ahdsr");
      const var knobGroups = [];
      
      namespace Envelope
      {	
      	// ----------------------
      	// LAF VARIABLES & Colours
      	// ----------------------
      	const var LineWidthValue   = 2.0;  
      	const var BallSizeValue    = 3.0;  
      	const var FillEnabled      = 1;    
      	const var LineEnabled      = 1;    
      	const var BallsEnabled     = 1;    
      	
      	const var BallStaticColour   = 0xFF6160D3;
      	const var BallHoverColour    = 0xFCCFFFFFF;
      	const var activeColour1      = 0x956160D3; 
      	const var activeHoverColour1 = 0xFCCFFFFFF; 
      	const var inactiveColour1    = 0x106160D3; 
      	
      	// ----------------------
      	// Knob Grouping
      	// ----------------------
      	inline function sortEnvKnobs()
      	{
      	    local numGroups = parseInt(knbs_Env.length / 8);
      	    for (i = 0; i < numGroups; i++)
      	    {
      	    	local group = [];
      	         for (j = 0; j < 8; j++)
      	         {
      	              group.push(knbs_Env[i * 8 + j]);
      	         }
      	         knobGroups.push(group);
      	    }
      	}
      	
      	sortEnvKnobs();
      	
      	// ----------------------
      	// Global Panel Paint Routine
      	// ----------------------
      	inline function pnl_EnvPr()
      	{
      		// Determine group index
      		local groupIndex = -1;
      		for (i = 0; i < panelGroups.length; i++)
      		{
      		     if (this == panelGroups[i])
      		     {
      		          groupIndex = i;
      		          break;
      		     }
      		}
      		if (groupIndex == -1)
      		     return;
      
      		local w = this.getWidth();
      		local h = this.getHeight() - 1;
      		local v = this.getValue();
      		local offset = BallSizeValue;
      		local lineWidth = LineWidthValue;
      		local padding = 5;
      		local bottomPadding = 20;
      		local slot = (w - 2 * padding) / 5;
      		local x;
      		local db;
      		local obj = [];
      		local names = ["Attack", "Hold", "Decay", "Sustain", "Release"];
      		local knbsOrder = [0, 2, 3, 4, 5];
      		local knobs = knobGroups[groupIndex];
      		local p = Content.createPath();
      		p.clear();
      	    
      	    // Draw envelope curve 
      	    p.startNewSubPath(padding, h - padding - bottomPadding - 0.5);
      	    x = slot * v[0] + padding;
      	    v[1] > v[4] ?
      	         db = (h - 2 * padding - bottomPadding) * (1 - v[1]) + padding :
      	         db = (h - 2 * padding - bottomPadding) * (1 - v[4]) + padding;
      	    p.quadraticTo(x / 2 + padding / 2, (h - 2 * padding - bottomPadding) * (1 - v[1] * (1 - v[6])) + padding, x, db);
      	    obj.push([x, db]);
      	    local dbA = db;
      	    x += slot * v[2];
      	    p.lineTo(x, db);
      	    obj.push([x, db]);
      	    x += slot * v[3] * 2;
      	    db = (h - 2 * padding - bottomPadding) * (1 - v[4]) + padding;
      	    local ddb = db - dbA;
      	    p.quadraticTo(x - slot * v[3], (db - ddb * (1 - v[7])), x, db);
      	    obj.push([x, db]);
      	    x = slot * 4 + padding;
      	    p.lineTo(x, db);
      	    obj.push([x, db]);
      	    x += slot * v[5];
      	    p.quadraticTo(x - slot * v[5], h - padding - bottomPadding, x, h - padding - bottomPadding - 0.5);
      	    obj.push([x, h - padding - bottomPadding]);
      	    
      	    this.data.objects = obj;
      	    local area = p.getBounds(1);
      	    
      	    g.beginLayer(true);
      	    g.fillAll(this.get("bgColour"));
      	    g.setColour(this.get("itemColour"));
      	    if (FillEnabled)
      	         g.fillPath(p, area);
      	    g.setColour(this.get("itemColour2"));
      	    if (LineEnabled)
      	         g.drawPath(p, area, lineWidth);
      	    
      	    // Draw those balls
      	    if (BallsEnabled)
      	    {
      	         for (i = 0; i < 5; i++)
      	         {
      	              i == this.data.hover ? g.setColour(BallHoverColour) : g.setColour(BallStaticColour);
      	              local bx = obj[i][0] - offset;
      	              local by = obj[i][1] - offset;
      	              bx = Math.range(bx, padding, w - offset * 2 - padding);
      	              by = Math.range(by, padding, h - offset * 2 - padding - bottomPadding);
      	              g.drawEllipse([bx, by, offset * 2, offset * 2], 2);
      	         }
      	    }
      	    
      	    // Draw label when hovering over control
      	    if (this.data.hover != -1)
      	    {
      	         local suffix;
      	         g.setColour(this.get("textColour"));
      	         g.setFont("GlobalFont", 12);
      	         local paramName = names[this.data.hover];
      	         local data = Math.round(knobs[knbsOrder[this.data.hover]].getValue());
      	         this.data.hover == 3 ? suffix = " dB" : suffix = " ms";
      	         local label = paramName + ": " + data + suffix;
      	         g.drawAlignedText(label, [0, h - 20, w, 20], "centredBottom");
      	    }
      	}
      	
      	// ----------------------
      	// Global Panel Mouse Callback Routine
      	// ----------------------
      	inline function pnl_EnvMc()
      	{   
      		// Determine group index based on the current panel (this)
      		local groupIndex = -1;
      		for (i = 0; i < panelGroups.length; i++)
      		{
      		     if (this == panelGroups[i])
      		     {
      		          groupIndex = i;
      		          break;
      		     }
      		} 
      	    local w = this.getWidth();
      	    local h = this.getHeight();
      	    local v = this.getValue();
      	    local sens = 200;
      	    local padding = 5;
      	    local bottomPadding = 20;
      	    
      	    
      	    if (groupIndex == -1)
      	         return;
      	         
      	    if (event.hover && !event.drag)
      	    {
      	         local closest = 1000.0;
      	         local objIdx;
      	         this.data.mouseX = event.x;
      	         this.data.mouseY = event.y;
      	         local tdo = this.data.objects;
      	         for (i = 0; i < 5; i++)
      	         {
      	              local diffX = Math.abs(parseInt(tdo[i][0]) - parseInt(event.x));
      	              if (diffX < closest)
      	              {
      	                   closest = diffX;
      	                   objIdx = i;
      	              }
      	              else if (diffX == closest)
      	              {
      	                   if (Math.abs(tdo[i][1] - parseInt(event.y)) < Math.abs(tdo[objIdx][1] - parseInt(event.y)))
      	                        objIdx = i;
      	                   else if (objIdx == 0)
      	                        objIdx = 1;
      	              }
      	         }
      	         this.data.hover = objIdx;
      	         this.repaint();
      	    }
      	    else if (!event.hover)
      	    {
      	         this.data.hover = -1;
      	         this.repaint();
      	    }
      	    
      	    if (event.clicked || event.drag)
      	    {
      	         if (event.clicked)
      	         {
      	              local KnbValues = [];
      	              // Get the knobs for the current group
      	              local knobs = knobGroups[groupIndex];
      	              for (i = 0; i < knobs.length; i++)
      	              {
      	                   KnbValues.push(knobs[i].getValueNormalized());
      	              }
      	              this.data.values = KnbValues;
      	         }
      	         
      	         switch (this.data.hover)
      	         {
      	              case 0:
      	                   if (event.shiftDown || event.rightClick)
      	                   {
      	                        knobGroups[groupIndex][6].setValueNormalized(this.data.values[6] + event.dragX/sens);
      	                        knobGroups[groupIndex][6].changed();
      	                   }
      	                   else
      	                   {
      	                        knobGroups[groupIndex][0].setValueNormalized(this.data.values[0] + event.dragX/sens);
      	                        knobGroups[groupIndex][1].setValueNormalized(this.data.values[1] - event.dragY/sens);
      	                        knobGroups[groupIndex][0].changed();
      	                        knobGroups[groupIndex][1].changed();
      	                   }
      	                   break;
      	              case 1:
      	                   knobGroups[groupIndex][2].setValueNormalized(this.data.values[2] + event.dragX/sens);
      	                   knobGroups[groupIndex][2].changed();
      	                   break;
      	              case 2:
      	                   if (event.shiftDown)
      	                   {
      	                        knobGroups[groupIndex][7].setValueNormalized(this.data.values[7] + event.dragX/sens);
      	                        knobGroups[groupIndex][7].changed();
      	                   }
      	                   else
      	                   {
      	                        knobGroups[groupIndex][3].setValueNormalized(this.data.values[3] + event.dragX/sens);
      	                        knobGroups[groupIndex][3].changed();
      	                   }
      	                   break;
      	              case 3:
      	                   knobGroups[groupIndex][4].setValueNormalized(this.data.values[4] - event.dragY/sens);
      	                   knobGroups[groupIndex][4].changed();
      	                   break;
      	              case 4:
      	                   knobGroups[groupIndex][5].setValueNormalized(this.data.values[5] + event.dragX/sens);
      	                   knobGroups[groupIndex][5].changed();
      	                   break;
      	         }
      	    }
      	}
      	
      	// ----------------------
      	// Global Knob Control Callback
      	// ----------------------
      	inline function onAHDSRKnbsControl(component, value)
      	{
      		local groupIndex = -1;
      
      		// Determine which group contains the triggering knob.
      		for (i = 0; i < knobGroups.length; i++)
      		{
      		     for (j = 0; j < knobGroups[i].length; j++)
      		     {
      		          if (knobGroups[i][j] == component)
      		          {
      		               groupIndex = i;
      		               break;
      		          }
      		     }
      		     if (groupIndex != -1)
      		          break;
      		}
      		if (groupIndex == -1)
      		     return;
      	   
      	    local knobs = knobGroups[groupIndex];
      	    local envelope = envGroups[groupIndex];
      	    local panel = panelGroups[groupIndex];
      	    local attributes = [2,3,4,5,6,7,8,9];
      	    local panelValues = [];
      	         
      	    // Assign the controls     
      	    for (k = 0; k < 8; k++)
      	    {
      	         envelope.setAttribute(attributes[k], knobs[k].getValue());
      	         panelValues.push(knobs[k].getValueNormalized());
      	    }
      	    panel.setValue(panelValues);
      	    panel.changed();
      	}
      	
      	// ----------------------
      	// Assign the Global Panel Callbacks to Each Panel
      	// ----------------------
      	for (i = 0; i < panelGroups.length; i++)
      	{
      	    panelGroups[i].setPaintRoutine(function(g)
      	    {
      	         pnl_EnvPr();
      	    });
      	    panelGroups[i].setMouseCallback(function(event)
      	    {
      			pnl_EnvMc();
      	    });
      	}
      	
      	// ----------------------
      	// Assign the Knob Control Callback to All Knobs in Each Group
      	// ----------------------
      	for (i = 0; i < knobGroups.length; i++)
      	{
      	    for (j = 0; j < knobGroups[i].length; j++)
      	    {
      	         knobGroups[i][j].setControlCallback(onAHDSRKnbsControl);
      	    }
      	}
      }
      
      posted in Presets / Scripts / Ideas
      HISEnbergH
      HISEnberg
    • RE: Pan Slider

      @JulesV You mostly just need to define a center point and draw from there. Here is a hasty implementation:

      Content.makeFrontInterface(450, 100);
      
      const var SLIDER = Content.getComponent("SLIDER");
      
      // Create a LookAndFeel instance
      const knblaf = Content.createLocalLookAndFeel();
      knblaf.registerFunction("drawLinearSlider", function(g, obj)
      {
          var a = obj.area;
          var handle = a[2] / 6; // Size of the handle
          var mid = a[2] / 2; // Middle point of the slider
          var n = (a[2] - handle) / a[2]; // Normalization factor
      
          // Normalized range
          var bipolarValue = obj.valueNormalized * 2 - 1; 
          var v = mid + (bipolarValue * mid * n);
      
          // Draw background
          g.setColour(Colours.black);
          g.fillRoundedRectangle(a, a[3] * 0.5);
      
          // Draw slider fill
          if (bipolarValue >= 0)
          {
              g.setColour(Colours.lightgrey);
              g.fillRoundedRectangle([mid, 0, v - mid, a[3]], a[3] * 0.5);
          }
          else
          {
              g.setColour(Colours.lightgrey);
              g.fillRoundedRectangle([v, 0, mid - v, a[3]], a[3] * 0.5);
          }
      
          // Draw handle
          g.setColour(Colours.whitesmoke);
          g.fillRoundedRectangle([v - handle / 2, 0, handle, a[3]], a[3] * 0.5);
      
          // Draw text value
          g.setColour(Colours.black);
          var displayValue = Math.round(bipolarValue * 100); // Scale to -100 to 100
          g.drawAlignedText(Engine.doubleToString(displayValue, 0), [v - handle / 2, 0, handle, a[3]], "centred");
      });
      
      // Set LookAndFeel for the slider
      SLIDER.setLocalLookAndFeel(knblaf);
      
      // Set slider properties for bipolar behavior
      SLIDER.set("min", -100);
      SLIDER.set("max", 100);
      SLIDER.set("mode", "Pan");
      SLIDER.set("text", "");
      
      
      posted in General Questions
      HISEnbergH
      HISEnberg
    • RE: Spectral Morphing in HISE

      @mmprod It's on my bucket list to do a deep dive into the Loris library, which I think has the solution. I have only scratched the surface here, but it is seriously impressive what it can do. My understanding with Loris is that it can't be used for live processing (though I could very well be mistaken on this).

      RNBO, unless they have updated their FFT objects, would be my go to but from experience I know it is not useable. Otherwise the task probably involves some external C++ which is not a simple feat. I wonder if @griffinboy , the GOAT for external C++ implementation has looked into it?

      posted in General Questions
      HISEnbergH
      HISEnberg
    • RE: How to draw super smooth Waveform?

      @mmprod I am still not done this but I am working on an oscilloscope I plan to share soon with interpolation to smooth the waveform:

      HiseSnippet 3945.3oc6Zz1Tabb9D3KoVIoMoMMoebKSSFgMHj.AFhKMHCRFl.HUIY6zZ6g43tURq4zcWu6DfZGOS+X+V+KzeJ4mP+MjeA4a8isOO6d6c6JIvDhMYbmnwCV6tOO6979K6plg91znH+Pib46LJfZj68MaOxKt+18sXdF6siQtOxrQjMy00Ox1OftZwJFOXTfUTD0wHWtYeHBVtaeKC9mu6KefkqkmMMaJCiG6yro6yFvhyls4VeErk0sbncXCTftxV6Y66ssuq+Pfjl0rjQfk8IV8nGZgfMiowtVQ8MxcGy0r2X0RGSKs5pqWYk0qTYsJqsZotkVo6wquVkiW4dUVwoxpksWwH26TygE6G1N1JlFYj6VOv2YT699m4INfGyhXG6RwAkMZCmrX559tNHKhyZrcelqSSorJxvH261LSxMqPx8wlGvbXoymIA+P9BjLLTEf4lQm7lUi7JqRdkTHuoPR4THoaIHoOxrscHKHNaEjddOy87hogcs.8jJoHf0Xl+ymXtsO.gWbwAVmPqGBCRwnPkRkVf.+Y96mO+R2gr4qkO4m1jjFs2du82G9ail0H6rW6l6W8OQdvipWuVKx2qc5574NKA72RjGaExr.EPTdvvLJlbpUHIvy8HvonLYShTP0iFus+f.eOXPg4j.LGHjVZoLDqeNhC2ACwnV2tTa.bXZDRU3lNXywE5KQdvPXpPzhJfFFyzHNo7IC+cXQAtViDH0F7r.sXxlog1QfjFoOwNLAlEJMAB6W6vG1YW.kxkVtx8I.k0h5Lzl5PNVPgtTudw8Ic8CIQwVGybYwiFaOZ1Bzts5rWs1v972xSfOyINv84HO2WnbTKHV+vgC.2KOOpaDrb47uDDKRFnXDMtEyqmXOxDQEzOLfWTwnpcL6TZg3vgz44LBeBvkjD2mlvM4Un7N0Nn4QohZwYUzNjBXTHibEaUGJXXDZENRJUPwQfvkDHz74Co837X68d3gU2G1utVtQTNt64whYVtr+JkXEIlOOd9Q1vjd8paYCwNPEPwRb32Yjm0.lsbc.CD.EBu81U2u1Q6TaavUZSRoharNGu1C78i6mgAmFcz2LtoGOPPfuqULy2iTe7seuC6TqUyF6WsydMN7n5U2tSCT.spf5.81w.+62kD3y7hiHw9DV5FBxYZ7YTpGIxZP.5xwc.YQCsbmts9AU+5id3tMZ2AscVcrinWee.r3PKlqJNa2X+FOp0QO3gbuWLQSTwicgrL2eRfZU8IJPERcD13VmQNy5TJHhFPrgECmDy1GznA2yPhbuPfwTD0fOxqbOp14Qsp1o1NJayHJjI9L99fSIzSQVwCCA4mCIfZchJy1tSqFeUsidxd6zYWz0d4DyjIoAP4aehGXQdAXurhQ1CyjrSEuF0q2tVmi3lZ7fCI38XTAB1Rf1oK3ywsqnbN3BzUBoHP.GtSim.tG+Y91s5XVrmw7b7OiDgNI3lY4EyVDrXs3dWJ6lPdhFlc1sUs161X+c39.BWfN8CoQ8gz9pxTvHmaEtM20lzzJtuJABEEgSojHPDC.mrfV3xPqytLHQBfuNd1gJFXJaAWHwo.XWd5ygXdHvEXHObeBi76U7Gfw28tySxKBnlgYwfgQ8KLMR.n1WlmGaoaHTr019C8h46Lm+qhxzpIxTRclK3zRpOzylKg3QjjlTBZi4AgL.8QBHIKmjIQDGbgDMWaPwkRpiyRBPKJRjH4JDPA33GWezlJZ3.A4pOscFeHWfeDu.lawC.NuXWWe+vBYjBYIxxfB4Eje+ljKEfTRQmbvOrtjB.WbWxKlm7GfCm74eNQNdLdRYOlbevOHic2MSP5o7M442eBn374cuq9BuL+jeSpmdJ64fH.27kDHKPU.XHEr98RgkaZ.VA6CpTLHudN.oUv3pbkH6sEAzSU7hjLoJcgpRAdoUzqzhfrHo7zsJT2MgUuTB974mhsPYtFOgvtbkqfZQipW.xtDLzU+W7YStCoPYfpimGTjJ5zx3Jwh.AIhYlpXdLMo3uW34LgLRxyIJVUDkJ2ES+.Qh..Hs7GFiJzrExKKrEKYhCTBLEjJ8B8xB5TrKziWUW2BoobwxWktG+1rJdlP2InRQAPcId9Pr8ddVtKPrN0m4PFBU9gEOgkT4.AKwv7BgB++vnQmwb3AagLDQXkrOAGWHQHf.zmx50OVAhc4SnBx.lCViTBjfSeB0iIe5y5Fmj0JfmSPyRUotDg8I4OvsdWbwIX0rPyBGR0wbE28UYsj7MEscACDIsljZIaRIUtsePZMmNVwVPlQmDeZBKlCUZMvPy8iZQsbRhPqTeqhDQFOHo+iM0ipqfyBSI0sx9nZ9ktWSIbg94svTqtTkesbsGxKjzY5kAKOerLo8omRcgiUgpQyflvRsr75QK.s4pTI+SkZhwq7lmhXf04EJUr7BIiXdEzA6Np0cu.oLXMkRCyqvA6fo9wNNzJAHU7yEK5z7SK8bcq.nOqv3Com0d3w7D6.avMjWTh9cDiuiNmHIhTa3xhnsYhfoGlEoKraU.mkTkWv9y8AyBLNUpmojJC2pQv5WExMCKIei4d53W37EHilWymQUrpkhQS9lRcSZalJhkdeulEwSdhWZ4NZR7KD2KSALEV7GtdPJbtP8fRjsRXjtDDFy3WsS.fAfHUmp20vqLR6lWTnVdA6AV1r3Q7x9WUlKFEjYaz75RB4w2Pzyxl5c2bGjLVTkL3EGlEdGyTJZdqfrGNjqp5Fz2pfVyhKHIt40v2Iw.ufVlhEHOEr5zosEDJ7ERxXAv72lqir8r49B814d4E6jLQrGMlHsy3jMPgBS9eAsU5UQNfB3kSKzWZiDWry5THHgLbRZJwJ6JRSZ8KiT2KStwMkhivarNDy03drk8IpUGo0Wn.rMI075AdDIsZwmrwwu.uOOXmkfgrC+KxcMqdpzxovZlx5L6t2k7YPZD7VRKMggt1cIU+b9kSNLLD53imvQbKWXIIEKUpLuJqGE3foMgyPToEwheeXo6XZcegz.rrOri0DyGoDpMFTjq.iQNQg2vE3esvJ3UHl1efu2g9wzF.OBr3sgpPIiuT2tScMr80PeWWXGm1xhy5RPrfG+Rh.+GKWPRHAzH2szuKdyK9t3Uep.aQ2zJ.56g2aWi.p2E8.BFIsfCe6Q6sCTaFdA9IykcUWvb6POkYSEWm+sM2gFcRrefQtYRusYibuSLe0OPdY+VdTWCliQt7lR8lw4puHyH0AbGhrIFskv0HcluIbKCkC68iSdrCwgU20GZOwqWGFHWvy7WXpN0Edv+q3sdUG7e+OtUh.Qv84M+J5ni8sBcLNtm7IhdeyJKudk6s1FqrdICVLcfbg2yrxpKuw5UVekxJyur.iMprwZ2a4MV0Hlddr5qMw0Dy77blnyzbv4w6a.ui4JEKgW97bIWIdC6XHfj3xFgk4WLKe888OCPClZC9vcYhQkW9d7waOLJ1evCCsBfnNQZXtCsq0P23pAPkgg3inAqhdp7Ee.dCkvV0BaFjG7bsM3eVe8R2aiR2qLGpN9854ROv2gpsy3yOkbe4Hovm6QQzGSwL3JzR5oAKVGB61Ndj6X6TyZRkv3yy8+yNkkkyWyyQ4rWK+KMLl7gp9PSfnwR20e2L70ESV.bf0drJ7NH7hfrkpu93qsGS6pRhejYSVrc+oSiyLEZDbyeSPiIOA4GXJdqnLB7Vl0+52Pu23rJm+6JN+2yrs3ZSSdow2OabY8mZL81UUEMOgFWc.lcSUm1Ljp+Hy.iCEBM9b4l8JyWk+d+NpSU2+olYbA4GGqTwsuzCZ5LjAAZMg3Qh22S95Xvb4lAy1HFWBGiDQapmCev+E9jrXYbbtjEKKWT0JyTFHNI1+WKMwNWioApP6gCiR2XwCLm6eXlkTN.qnHD5XnI.eAQuFPPN5Bjic8sOge2vSjIO4wyd.BQA6Dd85jv+cdMYzbinIxJY3PZ7Y9gmvsVS9N3CJ731IJPNUU7shvb2rDSSASAZD9f20DJ.rXIAXM8cGEz22iYipPARRhW5TJ3fcsh5.cmgA3ZOLBpwwogWa.X9O6CH.StCg7OfnUzf3Hr5aLPIVkD35fOSZpKjF0lYBgxXwO3CM.v8UlrVH7.xb.upjYLArv0EhDAAHNAenIIgYkgFE8IJTjBLSmJT.35PE+bSekeCMiSGVPA2ihnE0fYZzwXayqhRPknK8bY0ki4SN9LFX9JG54hCrF3u33Pc3HiamQSKr4iXpL0irDU8UfnmxQ.Qc.y6wnGG7UzVy3.qySGCETYzNlFfd333xvXgrpgTXCNTFoviqqct7.03nQHoy006EIehQIdfE6ER3W0M35Tf9TJf3WatKT1jMnzbHGXEwe.MQDTSHBpV9wYRcp0b.dski6lNwwmJKO3IPQy7eWJb99WyGye94GRA+vIqSPOK++9p9yKK3J+yKSTGeGnd6n.+HneEkctMc.qCz1Sj1rigwxSECsY2gFOzSeqESIgZqUVY1uAEE0AQgJbaImTY+93sfF7z1LXr14c.S1zE4Y+yu8Kq4g+9kZSAN2Q7S4iWelZIVCg534c5Td5Sur5znULnCsurput0Uyx7U7ir6cdS8ir6VWsJttbx6sf1Xzpk81RZrMCyKTy6TpKlFAoweoYR2mxY0cCOv2yWVbPlRuEEhdzqGUyVZpLT03Xn8UUa3VTWpUjhq4uaKwqdd.Oq40RV7Zpt9eiofb4Wz2OnB6uQMytzVQm8J0J5qc5852V5MrGJDx7sGM8mh+hrWlvU2je7022v0R7qj1TUG5v722GKEiKV9XwLDbJB1MIUuXhYdiWLAlUb73WbsDTsf8IX0rJGERlhTyNpv2x2OFu6a0eq7hmCmeAav1qGBFqUlpMWcnWLQ+BiL29Kd1ih.Hd1.1Iz+5yRpN8YbAkXWe1ZKW5dqs9QGY0e.CKT9EGczfgQL6EiwRbXnkUOX5Ei.6jEEq.UrsH9D4gKdVeZHcwyv+4Eu3Yg.rEGDrhw.TRKzxCrPihbdeVICWfk4bgbMWtLvQt9alpHt0OUEwOVUQr7OUEwOUEwa8UQbCmf6mmdW5fobVyxeBeLA6H7B5Vdla5tkmZqupShuiTH8uvezJ04212JbpK8ceYcfImJNYW1t1aD7uB17a+x2xRb7F+YodqLYwJ+Txhe3IK9w8EOm8+qewyajDA2Dmw.K6P+irEuMFZm9y3y.7sGuugaad.NlT13TwkfmoKG.Q4Nx1Veql.wkutHtx0EwJWWDW85h3ZWWDu20Ew0e0HhIgpNL1efv0zv3fl0DOgStzdMyMqw+CFi.0X
      

      This was vey much inspired by @Mighty23 's approach but with some distinct differences. To be honest I was struggling with it and used chatGPT to figure out the anti-aliasing filter and linear interpolation functions, i.e. it isn't completed yet. Use a noise signal and compare the green with the red output to see the differences.

      Perhaps you could employ @oskarsh suggestion with downsampling the signal for further smoothing. Also if anyone can figure out how to compress the signal on the vertical axis based on the amplitude would be a true hero.

      Content.makeFrontInterface(400, 400);
      
      /* ======================================================================
      ==================== OSCILLOSCOPE DISPLAY BUFFER ========================
      ========================================================================*/
      
      // Variables
      const var pnl_Osc1 = Content.getComponent("pnl_Osc1");
      //const var Fx1 = Synth.getEffect("Fx1");
      const var Fx = Synth.getEffect("Fx"); // Your ScriptFx with an fft analyzer to reference.
      
      // Buffer Properties
      const var BUFFER = Synth.getDisplayBufferSource("Fx");
      const var BUF_OSC1 = BUFFER.getDisplayBuffer(0);
      const var BUF_LENGTH = 1024; // Reduced buffer length for stability
      const var BUF_PROPERTIES = {
          "BufferLength": BUF_LENGTH,
          "NumChannels": 1
      };
      
      BUF_OSC1.setRingBufferProperties(BUF_PROPERTIES);
      BUF_OSC1.setActive(true); // Activate the buffer
      
      const var TEMP_BUFFER = Buffer.create(BUF_LENGTH); // Temporary buffer for processing
      
      reg BUF_SIGNAL = false; // Initialize as false
      var scalingFactor = 1.0; // Dynamic scaling factor
      const var SCALE_DECAY = 0.98; // Smoothing factor for dynamic scaling
      
      // Interpolation Factor
      const var INTERPOLATION_FACTOR = 50; // Number of points to interpolate between samples
      
      // Visual Properties
      const var MAX_GHOSTS = 5; // Number of ghost trails
      const var COLOUR_BG = Colours.black;
      const var COLOUR_RAW = Colours.red; // Raw waveform color
      const var COLOUR_SMOOTH = Colours.green; // Smoothed waveform color
      const var COLOUR_SATURATED = Colours.yellow; // Color for saturated peaks
      const var STROKE_WIDTH1 = 2.0; // Smoothed waveform thickness
      const var STROKE_WIDTH2 = 1.0; // Ghost trail thickness
      const var OFFSET_SCALE = 10.0; // Vertical offset scale for ghost trails
      const var SMOOTH_WINDOW_SIZE = 15; // Smoothing window size for anti-aliasing
      const var SATURATION_THRESHOLD = 0.8; // Threshold for saturation
      
      // Create Paths
      const var oscPath = Content.createPath();
      const var rawPath = Content.createPath(); // Path for raw waveform
      const var ghostPaths = [];
      
      for (i = 0; i < MAX_GHOSTS; i++) 
      {
          ghostPaths.push(Content.createPath());
      }
      
      var frameCount = 0;
      
      // Anti-Aliasing Filter Function
      var smoothed = [];
      inline function smoothBuffer(buffer, windowSize) 
      {
          for (i = 0; i < buffer.length; i++) 
          {
              local sum = 0;
              local count = 0;
              for (j = -Math.floor(windowSize / 2); j <= Math.floor(windowSize / 2); j++) 
              {
                  if ((i + j) >= 0 && (i + j) < buffer.length) 
                  {
                      sum += buffer[i + j];
                      count++;
                  }
              }
              smoothed[i] = sum / count;
          }
          return smoothed;
      }
      
      // Linear Interpolation Function
      inline function interpolateSamples(buffer, factor) 
      {
          local interpolated = [];
          for (i = 0; i < buffer.length - 1; i++) 
          {
              interpolated.push(buffer[i]);
              for (j = 1; j < factor; j++) 
              {
                  local t = j / factor;
                  interpolated.push(buffer[i] * (1 - t) + buffer[i + 1] * t); // Linear interpolation
              }
          }
          interpolated.push(buffer[buffer.length - 1]);
          return interpolated;
      }
      
      // ---------- Paint Routine ----------
      pnl_Osc1.setPaintRoutine(function(g) 
      {
          g.fillAll(COLOUR_BG);
      
          if (!BUF_SIGNAL) 
          {
              return; // If no signal, avoid unnecessary drawing
          }
      
          var width = this.getWidth();
          var height = this.getHeight();
          var midY = height / 2;
      
          // Shift ghost paths
          for (i = MAX_GHOSTS - 1; i > 0; i--) 
          {
              ghostPaths[i] = ghostPaths[i - 1];
          }
      
          oscPath.clear();
          rawPath.clear();
      
          // Copy buffer data and smooth it
          BUF_OSC1.copyReadBuffer(TEMP_BUFFER);
          var smoothedBuffer = smoothBuffer(TEMP_BUFFER, SMOOTH_WINDOW_SIZE);
          var interpolatedBuffer = interpolateSamples(smoothedBuffer, INTERPOLATION_FACTOR);
      
          // Calculate dynamic scaling factor
          var peakLevel = TEMP_BUFFER.getPeakRange(0, BUF_LENGTH)[1];
          scalingFactor = Math.max(0.1, Math.min(scalingFactor * SCALE_DECAY, 1 / peakLevel));
      
          // Draw the raw waveform
          var sample = TEMP_BUFFER[0];
          rawPath.startNewSubPath(0, midY - sample * midY * scalingFactor);
      
          for (i = 1; i < BUF_LENGTH; i++) 
          {
              var x = (i / BUF_LENGTH) * width;
              sample = TEMP_BUFFER[i];
              var y = midY - sample * midY * scalingFactor;
              rawPath.lineTo(x, y);
          }
      
          // Draw the interpolated waveform
          sample = interpolatedBuffer[0];
          oscPath.startNewSubPath(0, midY - sample * midY * scalingFactor);
      
          for (i = 1; i < interpolatedBuffer.length; i++) 
          {
              var x = (i / interpolatedBuffer.length) * width;
              sample = interpolatedBuffer[i];
              var y = midY - sample * midY * scalingFactor;
              oscPath.lineTo(x, y);
          }
      
          ghostPaths[0] = oscPath;
      
          // Draw ghost trails with vertical offset
          for (i = MAX_GHOSTS - 1; i >= 0; i--) 
          {
              var opacity = 0.5 * (1 - i / MAX_GHOSTS);
              var verticalOffset = OFFSET_SCALE * (i - MAX_GHOSTS / 2);
              g.setColour(Colours.withAlpha(COLOUR_SMOOTH, opacity));
              g.drawPath(ghostPaths[i], [0, verticalOffset, width, height], {"Thickness": STROKE_WIDTH2});
          }
      
          // Draw the raw waveform
          g.setColour(COLOUR_RAW);
          g.drawPath(rawPath, [0, 0, width, height], {"Thickness": 0.5});
      
          // Draw the smoothed interpolated waveform
          g.setColour(COLOUR_SMOOTH);
          g.drawPath(oscPath, [0, 0, width, height], {"Thickness": STROKE_WIDTH1});
      });
      
      // ---------- Timer Callback ----------
      const var oscTimer = Engine.createTimerObject();
      oscTimer.setTimerCallback(function() 
      {
          if (frameCount++ % 1 === 0) 
          {
              BUF_SIGNAL = Fx.getCurrentLevel(true) > 0.001; // Update if signal active
              pnl_Osc1.repaint(); 
          }
      });
      
      // Start the timer
      oscTimer.startTimer(30);
      
      
      posted in General Questions
      HISEnbergH
      HISEnberg

    Latest posts made by HISEnberg

    • RE: FFt Spectrum2D

      @hisefilo Woah that is awesome! 😊
      Thanks for sharing!

      posted in General Questions
      HISEnbergH
      HISEnberg
    • RE: FFt Spectrum2D

      @hisefilo could you share a snippet? I’m curious what this entails(spectral processing, etc.)

      posted in General Questions
      HISEnbergH
      HISEnberg
    • RE: Which AAX SDK version works for HISE 4.1.0?

      @Sawatakashi It should work if the AAX SDK is setup correctly and the HISE-based plugin compiles successfully. You are correct that the Pro Tools Developer let's you test usigned AAX plugins. Have you tried testing a simple plugin example (like a single slider gain fx) just to see if the error is with your SDK setup or with your plugin? I am using the 2-8-0 SDK I believe

      posted in General Questions
      HISEnbergH
      HISEnberg
    • RE: Help with LAF slider text position

      @DanH I have this one if you are able to scrap it for your purposes 😊
      It work's best when the dimesnsions of the slider are square*

      HiseSnippet 2007.3ocuXstbiaaElz6psYUaSSloO.X7zsCkWFtTTV9R1YGe2odVeQijSlMiG2MPjPhnlhPCIjjUR1+02j9Hz2k9BzWf9+8GoG.vKP1xWy1xYrEv4F9vAmyAWZkv7IoorDCypmNcHwv72UoyzXd3NgXZrwA6ZX94UNBmxIIHEosmNDmlRBLLMex2HHX97mZH+9OarMNBG6SJIYX7cLpO4P5.JujZqMeKMJZeb.4T5.MoWdyC7Yw6vhXi.77jJtFCw9Wf6SNFKDagJF+EbZng4RU5V22kznqOF2EuNYs0Z1c40VccLodP8Uatx5McWu6JMWcEeCymsW.kyR5vwbRpg4S2lELsSHaRrZ.9NZJsaDQzotQGXjUj2mEEHlhBpF6DRiBZk6nRM.qzpzs8Dka6OV4HZ.sfdo66KjLPkZn6.MWXV38jYfW8aBdyARlZP5oJH8kU53mPGxK4HvyusxAwvpYOLrNoCEkrFKP+CU1gARDycFfufreBzoPCKOWWaD7uZutZUXsJkiFiSPQ3du+hXVWOzaP4J6mPf4zgLebzgL1EaEGrOgDYAJVp2aAcpqoSeBeG1fgrXni0hRtKdME7tUE7DJTUppSJgeswu.pfXR4uSop9pWgdy79DLd6wmr8Wi5r0QsNbOzd6dvomz9lkuvpNIj9TQN09ih84TVr0hAI3IsYbbxzNQz.Rxh1nd4L6aiXc+a0p9SUQvGX95NnswoDz.BOg5mh9ynti50ijH4K7SXvGAp3fgEAazDnG9LuysQgxVMN+0ERtKP4HLOzY.M1ZBHQsRdI.ucQKgbcZ7Zwv1ljR+Qxq5.NKRgP9WJso64nWhl7JOaj+TIg5BBgK45rL3ByvsmCZ2D1PTZHNfMovDAzTePm1DeNNteDwBr4WgRjlR9axRdx+ogMkItV7VKXp.wXYrcvAA6EEQGlRrDCRl98cDdaAR5HEChwGHUToksDP1HUgnTmITd3VQCCwV4T5FA0krA+x5MqI.lqSSazYtpldmWqbF2vA0YT7EjXTBMteI5UzdibjbHWNDGC0arRTNa2BbBwleSBNfBSv8gRlVmIoK9tufSMRvxSQy5maeOrR+DxTgQ7.afJsBrll01S2hkjanYcdxHUbx4ESndvrHeEQoglyZYGzIiD6zzk7ijnBmkr2M3q79D4qbgoobbjdJUq6mipvD00LA3OTM8zrVAwGfORpflKpoCZqD+YClvI9mFR8unHa00605LaiCfNuAI7X0cbaNKSHoSv7LYNmR5rDu7NpeEof4szpezsu.OR6O+LQo.hDQ3GqrAzF8UdhTF3eqpu9o7oVW2YKpkQ4jAJN0kqXqUalzY43IGLazO8A6BuhVMiw3HEXuArVHHINXKjZRI.Jrv4431XIn4RBj.1YD4XVx.bDTOLHWunaZhtlszh2qYpbpFxFSR94eVzzOBlCjfZafthO.80Wghmc843QTv5Ztj73oUbj6ohDatCaiDR6GFA+wS+UjTMID.UdFwUJkeKpKlMc6qnaKBTUZ+xLseot12QViVsdwxY+HVZZdAjDRvH+h5GtM+UU+nbpJp0JGGYADUq6WAjBaHlvE1.lupldZlqf3CnBhTAMmQWx3xpoWwYr5mFmAjZZqFmrpoie3UScapYCYkywEkSGWVNc7cWNUjJTVNETvFkMcWVKQXUGzAwATeLbZbT.iWVizUVGPdFoVG.6uuJT3BWWijmimdM039B4A0dIxBjCpi5VCFuaovALfsKpPCwRZzemjtLMPNb9rTKXDpsj3jFqAFOnslzeuR5o4RmBmoatR++kZP5QgmE7N3XUeO7WawFIh+qeLo0bP6PDWx.0OgACbYpqr67CWaz7Syd+KKRckiiJ2U07Al7VW2Hh7TUaOcCVR9gj+J0PyWstC5PbWHGlStrLLkGJV5CUGJpLjfikatikyr7CkCAB7P3ZA1vOZakyujCxZoshqV9kQB0Jvq3aCU7UBaTbfUQjcMv3hNovkQnWNiBp.EAh0Vx1mIt01IWNsOIFtuScu4rCYtZptyjTuErSULI3TfqEfcX1.20YQeHF.hSDWC7CBuV07qQgXwGy3jShsD2j54U+PUzUY0q2b4INrPBKJhjLW1hGwH41TzJdzftDXaLkWJWP3h5yd6+mc+t8uu5rKZBxhOHlxOYHIq+s+7EFYG9wvvbgLDBhxkuYvmm8lApKgZPAi7apHuMsgD7YOVyOzq2+ZCi6sxdyn7lMZ7u2v3aOXWLGKd4hL3.PbHIgSEdBycIio9D06X77J6RRufyFJwa1s8ML+r6DwWp+zRSK67m1bBMfGZXVw7RnaHQbhm7dkEy.Ed1G+3G+mBUxOXhfFz8ak14A.FOcv7W0.yl+PIX7lALdWCL+8ew3ebUv7hW7BEXt96+7EUNhELJRril9yQIdztLFPT5LuAj3cdhSo7o5Op2C3Mpbu02n59BwurRKJ2Ob9Xbg4fQQf7+CvX1K686qrWudvY4KA3Sqr+6drOi2cL7sYi3vc6fpqITHhoxwiFzAVo8IvnGGShREQFKHh8T8cE8EdfNvMLjc9E3KiYcQeyLl0yYZL.6mvduuJ4U71geljBfoX46r97JGI5ilMkW9MfFPeuu+rl5ZJ58XUrwiUwkerJ17wp3JOVEW8wp3Z2shhWZdqQb1.UZigwQs1SVk0zbuXLDAJiVM9uvq3As0
      
      Content.makeFrontInterface(200, 200);
      
      const var laf_knob2 = Content.createLocalLookAndFeel();
      const var Knob1 = Content.getComponent("Knob1");
      const var Knob2 = Content.getComponent("Knob2");
      
      Knob1.setLocalLookAndFeel(laf_knob2);
      Knob2.setLocalLookAndFeel(laf_knob2);
      
      // =====================
      // KNOB: SAMPLE EDITOR
      // =====================
      laf_knob2.registerFunction("drawRotarySlider", function(g, obj)
      {
          // 1. Base metrics & buffer
          var a = obj.area, w = a[2], h = a[3];
          var D = Math.min(w, h);
          var r = D * 0.3; // Resize/Scale
          var cx = a[0] + w/2, cy = a[1] + h*0.4;
      
          // 2. Drop shadow
          var disc = Rectangle(cx - r, cy - r, r*2, r*2);
          var shadow = Content.createPath(); shadow.addEllipse(disc);
          g.drawDropShadowFromPath(shadow, disc, Colours.withAlpha(Colours.black, 0.95), r*0.5, [0, r*0.2]);
      
          // 3. Sunken ring
          var sunken = disc.expanded(r * 0.30);
          g.setGradientFill([
              Colours.withAlpha(Colours.black, 0.95), sunken[0], sunken[1],
              Colours.withAlpha(Colours.grey, 0.2),   sunken[0] + sunken[2], sunken[1] + sunken[3],
              true
          ]);
          g.fillEllipse(sunken);
      
          // 4. Outer bezel
          var bezel = disc.expanded(r * 0.20);
          g.setGradientFill([
              Colours.withAlpha(Colours.black, 0.0), bezel[0], bezel[1],
              Colours.withAlpha(Colours.black, 0.1), bezel[0] + bezel[2], bezel[1] + bezel[3],
              true
          ]);
          g.fillEllipse(bezel);
      
          // 5. Arc ring
          var arcThick = D * 0.02;
          var arcRad   = r * 1.05;
          var arcRect  = [cx - arcRad, cy - arcRad, arcRad*2, arcRad*2];
          var bgArc    = Content.createPath(); bgArc.addArc(arcRect, -2.5, 2.57);
          g.setColour(Colours.withAlpha(obj.itemColour1, 0.08));
          g.drawPath(bgArc, {}, arcThick);
          var valArc   = Content.createPath();
          var endA     = -2.5 + 2.03*2.5*obj.valueNormalized;
          valArc.addArc(arcRect, -2.58, endA);
          g.setColour(Colours.withAlpha((obj.hover||obj.clicked)? obj.itemColour1 : obj.itemColour2,1));
          g.drawPath(valArc, {}, arcThick);
      
          // 6. Knob face & highlights
          g.setGradientFill([
              Colours.withAlpha(Colours.white, 0.1), cx - r, cy - r,
              Colours.withAlpha(obj.bgColour, 1.0), cx + r, cy + r,
              true
          ]);
          g.fillEllipse(disc);
          var gloss = disc.reduced(r * 0.05);
          g.setGradientFill([
              Colours.withAlpha(Colours.white, 0.15), gloss[0], gloss[1],
              Colours.withAlpha(Colours.white, 0.0),  gloss[0] + gloss[2], gloss[1] + gloss[3],
              true
          ]);
          g.fillEllipse(gloss);
          var bevel = disc.reduced(r * 0.07);
          g.setGradientFill([
              Colours.withAlpha(Colours.white, 0.08), bevel[0], bevel[1],
              Colours.withAlpha(Colours.black, 0.05), bevel[0] + bevel[2], bevel[1] + bevel[3],
              true
          ]);
          g.drawEllipse(bevel, r * 0.04);
      
          // 7. Indicator dot
          var a0   = Math.PI*0.75, a1 = Math.PI*2.25;
          var ang  = a0 + (a1 - a0) * obj.valueNormalized;
          var dR   = r * 0.1;
          var dX   = cx + Math.cos(ang)*r*0.8 - dR;
          var dY   = cy + Math.sin(ang)*r*0.8 - dR;
          g.setColour(Colours.withAlpha((obj.hover||obj.clicked)? obj.itemColour1 : obj.itemColour2,1));
          g.fillEllipse([dX, dY, dR*2, dR*2]);
      
          // 8. Center groove
          var groove = disc.reduced(r * 0.35);
          g.setGradientFill([
              Colours.withAlpha(Colours.black, 0.4), groove[0], groove[1],
              Colours.withAlpha(Colours.white, 0.1), groove[0] + groove[2], groove[1] + groove[3],
              true
          ]);
          g.fillEllipse(groove);
      
          // 9. Label text
          var th  = h * 0.2;
          var ta  = [a[0], a[1] + h - th, w, th];
          var txt = (obj.clicked||obj.hover)
                  ? Math.round(obj.value) + obj.suffix
                  : obj.text;
          g.setFont("Oxygen", 12);
          g.setColour(obj.textColour);
          g.drawAlignedText(txt, ta, "centred");
      });
      
      
      
      
      posted in General Questions
      HISEnbergH
      HISEnberg
    • RE: Anyone willing to build my HISE project for AAX?

      @dannytaurus It's not that bad. You get a warning on Windows saying it is an unrecognized App, but you just bypass it *select "More Info" and select "Run Anyways", then the user is usually good to go. I don't codesign my Windows Installers since it is such a rip off for the certificates (but I am considering it).

      @orange thank you so much sharing that information! I saw a JUCE post saying you could do this but some users reported issues. Definitely going to try this! Is it more or less the same commands you run in the command prompt for Windows and Mac?

      Screenshot 2025-05-09 at 6.46.42 AM.png

      posted in General Questions
      HISEnbergH
      HISEnberg
    • FFT Analyser Path - Need help drawing the magnitude to height

      I am struggling to draw the magnitude/peak/rms of an analyzer to my path. My example snippet is just grabbing the analyser buffer from my scriptnode network and copying it to fill a path in a panel.

      After some back and forth with Claude my code has become a bit messy but still I haven't solved scaling the magnitude response of the FFT analyser to the vertical axis. You can see in the example that the signal level can take an effect on the alpha. Does anyone have an example snippet on how to do this?

      HiseSnippet 2775.3oc0YstaabbEdojVkHk3hj.Wj9yIF8GqbroHks7En3FIQQYITcgPTUoAtFBC2cH4TsbmE6NTRzFBn+r+q8gouH8MnnOA8Mn8LWVtyPtTRlw1IkvvZ2Yly47cNy41LaiDlOIMkk3TZwiGDSbJ84tMGDw6VqKlF4r6VNkVvscadCLuqylChwooj.mRkl8khoKsvbNxe+mueSbHNxmjOjiyILpOYOZOJOezFq+6oggaiCHGS6Yr5Gu9t9rnZrPVe.Jy5VwIF6eFtC4.rXYy35rCNsqSo661ppeExiZ4iwsvOm7rmsZqG+rm9bLoZP0mt5Sd9pUddqmr5SehuSo4qGP4rjlbLmj5TZtMYACZ1kcQjR.mPSosBIhWp5zDjrZ3sYgABUTLpSstzvfFY1nTGmRtMxsXyprX20ceZ.c334VtuPNAJmBSCXoYrg2rVvq5jfWAPpjAjlSAouzsoeBMlmOi.Oel6tQbRRaLrOYBE0Zcl4e9Ut0XvJh3k6gOircB7xPJ7dbkJO.sRkJKs1hnEifskTXKhf1mFQ6gC2tMeiHb3fTRxhucQD7a4kQ0XIDjOqWLKBXZpbXXaNkiNGmfRg8ZfAu.Ic3J2gv2hlFGhGrY+1sIIMkS6cu1WdOgHsHE7HE9OI.w0i5PiHk8SHfcTN3gs9yDet2XDEGEdJ.SflLsDDYsLz4cO87UxDWlVnQEpkDVxQ0Ksb.liKqFGXqRgFSQ7pnYXATUNkv2vmSOm3wS5SJZgwPnmAlUJpHdzaDbp2roQczP0zfKFA3hBQZl3UDf.zeDAGng9RkCIQc3c0hJgzAEhS4MXTX+D32qd8ZKluaG0l1oeBlSYQJwhs20Odmip2bmC2aKfxpkqrVF3Uy1b2WdvF6c5V0qswOBKnR4pqYO8d0OnV8SMYRkxUprp0p1Z2lM1aie7zM28flvBVs5JVSuS8ce4NGeZyZarW8gfvxLw4.3mjKxlxoqNpGhLFV3iQwPHa5PSUJsCDSrG4bRnBrZrjQmhcHebXXKHcGpMKAQh.d.6gKGPSUOg3cIns29XIUzHXHBpc+HeoYlEowj.vIrPuggaO..TH3RIISERJYPajmbBzK.8eogiK9kEVUF14RTO58nLuWwORXJYRTvhUDnW9U4ZpxnJb00frlVg8FE8iXW2Mhxo3P5aHY1.T5fTNoWglB5vU6MpRm4nCPnAjcleDqOGn0SVYK+cCMseLDTP.I5YLXt1RTOLTQFt7BWcAVyqrTz8APfhEHAknfhzWHSoiwQjvB04QT.uNip4gLv6B0h0OJPDux6RSE9z6IFdS4ndlavpkeArREIuZkWO5jcym7QiMoNYkTLCydkungOzQ4MHJ26o9SZ4Kn7taDF2E6U4xs0+dfYLzRF.sS41PiDxzfBQ7.zqfpSv+t3AntutPa7VDNTVHUyPTnLprcBqmNaIRf2BMxARJalCDuhsx8vc.Wv9AhZZBdJLz6mMlG.N4fVITyINE9Ox1Xenk.QdKHWw3VM67I6C5MTn9Rub4deS1XY6foLyuZH9hXJMxCRMZa7K.OIDd+jHyUUjgeGbT.jUDVFn5PAePAOmjL.z6KzjVnUuqjrlJhzaxhc2Qs8h.EOpH+5ZHJ56LpOoM0vve62ZmnKeMuh9ZfztKuRApmPlkEf5XlmPxKuhgQ3VOYkBmzOjkRZ1ukYg7hrs4wO1F0CXI8j45RybekI0SQbFpMMJPl6.bNn85Wb1xnLFnqzCtL8gTBznzI4be4IXcYLwOn3rnxGviPfWQO7MjDlBCiqKitEkKqB1aDEnjdg3VodBcC1hVB86z.vdsheCA1XDMYqphlhrq0jcFkZj5ERnIxLgXwb3rLugDfhkdNEZUUMVsMMD5ZlDn1bu9LxYkl9fjTt3ryStUxgtmxRVGPtHyCcLm3Q3b9NpYNDylwlT1ugOTPV1BVkv6XrHbz27Bzn9u1Fc6fdciqVMx7t3hdioPtpXfalp86FugVagncUmXZvItWLLf3ZBwW6mPP5HVUkmEKkJC.z69grNdUQeKhtDZY6QJDD4L5RQHQFytO5B60T.ACUxfSTc0Ndd..BlA71zOPs2gdHxaTVceHr59VGYXoqANCLKICwKCiBfMrAKccTZkwa.fDKeKH22KPSvG4si4VZV44RgfW6F8bGXujqrdarN9uQQZC9Iw6qtwxsF7I2m4gUe8ubpAK6ZW04uQE.nfHTin0.YIDtnq+BqTXb.iIbXEySk6yhGXbrbwnlZSA2WPQUhFmhDh7TGdE1wrwwuHhN1ft5i5nUl7iZs1hWYbZzCXbxgQfN81EWXQfciNU61ENm97eghyOVvz5SVNYB8h52qEIY3Yd0Kzozb12x172taYyWUgzXgrHg03vXh98q+ZBczkXE2NmFgvR4x6l6WouaN0IecnAhqXUeLXGI7MuDUm+vtaA6pYLB3IHmXRBmJTmRaQNm5STW52BtaQROCNGNHpg2YAnxJwdmrqDTbVRoTWzM6FubtzTjCLe4BZ.uqSI2R+8RNNcIzNc4h29GNRkbTgbs51DDxeo85CERCGSgb2QDxmXqI6gao0jO0U9rkHNd8hEwSJMpH3jKgmumaSQOO4Qspt9Dupt+huwwY7KZ8Kb2mEzODysu2Wwsiqm.bSstrUwEpFA02FXd64uCWFbkq8xfusP7KcaP49cKFiyT.FAGvODXTeE52wsNjWymmCv4b29ONs2Wdka+8k6pj+hZWJPlJg29RKgeP+dVWoapv2AbjbzWcdo+padRoXQR0DnrSCX8do3dwgji.PCc.CsbbVSHq43YxhUXZSwJ77gl9fnzzoIg27um9rBNpqTpCzXRBEhqbAaf5J4qoQmvFLiHBU8dEw6BGkljn.4K+W3mdxpCMXvjUylLOMoyAD9Erjyj6O5mg.dwlgq36O4rQXH6BQt.p1eE1Uji0fENHtKKh5KFRshLHtQO3HQ7LbtCN8XLMT3f2reJjIO3vHce0BROA1VkL9Sbgi3VFzfYNfE.SMu55TFH+FXPjin3.3lJpJOzcUARKWF4GtRMtfOYeaKkMBvYOYNsYbgM.iT5J2SwaPv2LBV+4t6ldhXVnyBmST0G.8QvSk0RARwRmWHMn1jIduiKV8cYJWLB0z7t.QYN4PxkYElFIzXzQD5QT.4xLFWGbbCfhmRxy7DZfS.3vIpDDlurIicVOrz0XpJFZlt4qUS9Yt+.9bh7yNI2890x2gC.0C8RBrwJxUV88wm6L9V+4NOzmCP33DbTJb7GRUSN2jzidLTCL0ZzQnXkBovZzsf1YirYsZHqUILEaClhpl5a1fFq7tqCsRXwL3cKNsOMqdL5O8292eecwW1fzj.Zdvgo9fgQXmMkRi9voM9AQkZC99uLFdEyg2AmD.6g9VEol859nuSL8mc8Zi0WP4i4+P8Efm61UQ6F577W98nXU.dgLL1jJxoTO5bRHDRKw3WAwvsw8C4YiZGStOKhkk4O2C3HBTupSGhkiUgJzFbN1+LSG5iHgDbpQb5uc88fD83j8k4XmJaw69Guuv8qeiqBtHQhDzOk8sOptYWaelydq5y78Ndm9dN+HGgB4O++mc5u1ExouBRtci94e+9iQ2qeLjQOreB6TeUS+hDFepbDPuijsusf69h2QEb0A8fROm56aypwHbkokvGMsD93okvUmVBexzR3SmVBe1MSnnyfM5yY8TwIP6RMpqZItjpSIYHiy+iaEPMY
      

      fft.gif

      Content.makeFrontInterface(400, 200);
       
      namespace MinimalFftAnalyser
      {
          // Core components
          const var source = Synth.getDisplayBufferSource("fx");
          const var fftTimer = Engine.createTimerObject();
          const var pnl_Fft = Content.getComponent("pnl_Fft0");
          
          // Display buffer
          pnl_Fft.data.buffer = source.getDisplayBuffer(0);
          pnl_Fft.data.buffer.setActive(true);
          pnl_Fft.data.path = Content.createPath();
          
          // Processing buffers
          const buff = Buffer.create(pnl_Fft.data.buffer.getReadBuffer().length);
          reg lastPoints = [];
      
          // Configuration constants
          const THRESHOLD = 1.0;   
          const SIGNAL_DECAY = 0.1; 
          const SILENCE_THRESHOLD = 0.005; 
          const DISPLAY_BINS = 512; 
          const HEIGHT_SCALE = 1.0;  
          const button = Content.getComponent("Button1");
          
          // State variables
          reg signalLevel = 0.0; 
          
          // Button callback for enabling/disabling the FFT
          inline function onButton1Control(component, value)
          {
              if (value == 1)
                  fftTimer.startTimer(30);
              else
                  fftTimer.stopTimer();
          }
          
          button.setControlCallback(onButton1Control);
          
          // Initialize the FFT system
          inline function initialize()
          {
              pnl_Fft.setPaintRoutine(fftPaintRoutine);
              updateFFT();
              fftTimer.setTimerCallback(updateFFT);
              fftTimer.startTimer(30);
          }
          
          // Main paint routine for the FFT panel
          inline function fftPaintRoutine(g)
          {
              local bounds = this.getLocalBounds(0);
              local w = bounds[2];
              local h = bounds[3];
              local path = this.data.path;
              
              g.setColour(Colours.withAlpha(0xFFFFFFFF, signalLevel));
              g.fillPath(path, [0, 0, w, h]);
          }
          
          // Detects signal level from buffer data
          inline function detectSignalLevel()
          {
              local magnitude = buff.getMagnitude(0, buff.length);
              local scaleFactor = 5.0;
              
              signalLevel = Math.max(magnitude * scaleFactor, signalLevel * SIGNAL_DECAY);
              signalLevel = Math.min(1.0, signalLevel);
              
              return signalLevel;
          }
          
          // Handles silence or very low signal
          inline function handleSilence(path, w, h)
          {
              for (i = 0; i < lastPoints.length; i++)
                  lastPoints[i] = h/2;
              
              path.lineTo(w, h/2);
              path.lineTo(w, h/2);
              path.lineTo(0, h/2);
              path.closeSubPath();
              
              return path;
          }
          
          // Normalizes buffer values to find the maximum
          inline function normalizeBuffer(actualBins)
          {
              local maxVal = 0.000001; // Small non-zero value
              
              for (i = 0; i < actualBins; i++)
                  if (Math.abs(buff[i]) > maxVal)
                      maxVal = Math.abs(buff[i]);
              
              return maxVal;
          }
          
          // Creates the FFT path with optimized points
          inline function createFilteredPath()
          {
              local bounds = pnl_Fft.getLocalBounds(0);
              local w = bounds[2];
              local h = bounds[3];
              
              local path = Content.createPath();
              path.startNewSubPath(0, h/2);
              
              local actualBins = Math.min(DISPLAY_BINS, buff.length);
              
              detectSignalLevel();
              
              if (lastPoints.length != actualBins)
              {
                  lastPoints = [];
                  for (i = 0; i < actualBins; i++)
                      lastPoints[i] = h/2;
              }
              
              if (signalLevel < SILENCE_THRESHOLD)
                  return handleSilence(path, w, h);
              
              local maxVal = normalizeBuffer(actualBins);
              
              for (i = 0; i < actualBins; i++)
              {
                  local position = Math.log(1 + i) / Math.log(1 + actualBins);
                  local x = position * w;
                  
                  local normalizedValue = Math.abs(buff[i]) / maxVal;
                  local y = h/2 - (normalizedValue * h * HEIGHT_SCALE);
                  
                  y = Math.max(0, Math.min(h, y));
                  
                  if (Math.abs(y - lastPoints[i]) >= THRESHOLD)
                  {
                      path.lineTo(x, y);
                      lastPoints[i] = y;
                  }
                  else
                  {
                      path.lineTo(x, lastPoints[i]);
                  }
              }
              
              path.lineTo(w, lastPoints[actualBins-1]);
              path.lineTo(w, h/2);
              path.lineTo(0, h/2);
              path.closeSubPath();
              
              return path;
          }
          
          // Main update function called by the timer
          inline function updateFFT()
          {
              pnl_Fft.data.buffer.copyReadBuffer(buff);
              pnl_Fft.data.path = createFilteredPath();
              pnl_Fft.repaint();
          }
          
          // Initialize everything
          initialize();
      }
      
      posted in Scripting
      HISEnbergH
      HISEnberg
    • RE: Changing Scriptnode Drop Down Parameter Via Script

      @scottmire I intend to work on something in the near future to check for loud pops and temporarily drop the audio signal (almost like a brickwall limiter), or some other method. I have this issue too with some saturation algorithms (plus the soft.bypass introduces some pops of its own). If I figure it out I'll share it with you.

      posted in Scripting
      HISEnbergH
      HISEnberg
    • RE: Changing Scriptnode Drop Down Parameter Via Script

      @scottmire Ya feels like there should be a way to reference that dropdown. It might not be ideal but you could create 5 individual networks for each nn and use the scriptFx or Hardcoded Fx and swap between those.

      posted in Scripting
      HISEnbergH
      HISEnberg
    • RE: Changing Scriptnode Drop Down Parameter Via Script

      @scottmire You could probably just use the soft_bypass container (check the template section in the nodes) and bypass the ones you aren't using

      posted in Scripting
      HISEnbergH
      HISEnberg
    • RE: [bug] Draggable filter spectrum colour doesn't update when it should

      @d-healey This seems fixed, but for scriptnode (hardcoded as well) analyzers none of the colour are applied from the property editor

      HiseSnippet 1509.3oc0WszbSbDDdVKOFr.BgTjhbbKW4fgxkKIY7qjC3GxBTEjshkvvMpQ6NxZJu6Las6r1Vgh642R9EjSoxwbLWyM9IjSbkzyL6JsqrvHDORhzE0ulom9wW2pYnvgFEIBQVEa2OfhrtNtUetr2t8HLNpdUj0WfaPhjzPaCqc5GPhhntHKqBOTwvZ9YQ5O+8C1g3Q3NzgrPniDLG5iY9L4PtM25GXdd0Htz1L+LZe+sp6H36J7Dwf+T.WBEPbNgbLcehRsYvnGQh5grtGtSYmRzU53PHcHaR2XiU6b+MVeSBsra40WcsMWszlcVa00WyAYM2dtLoHrkjHoQHqY2Q31uUOwYbyEbDKh0wipHJiZA2rgcMgmq5Ip3h1sGyysYZfJBgrvMGF1JXBa2F2f4xFveX36K0BrGZQ1.n0L4cuB4buxuM2aLtjUFWZViKcKbKmPVfbnDk+bMbcNjM6Rf7TVWwnKx52w6J.E3xk8ImPqEBDCLXwUJUZI6JkJc2uuaL2QxDbaAeegjd.ew6V7EEmu3KKZOpntcGqL00DJ77ngiUrpzH7xLbQdreGZ3R1mR7hoCTDd94ioyMYwTGyqNihBdcNSdP.Mg9xKJPIgM3WOodUhjnRJI7.8BngRlxcrpROEZILon4wUoQmHEAZc8CDb0IXcCYRMkIoTySPjL9wsYfay.O3l3rrJiNOaGW+rDINf41tId6XWlXaNwqeDMD043zds4m60u90uQY.SR8GxEg9qQ3VwvFoYKomKyprgq9waUE+hh11KLHDU2cguydgtKrjhactK8bftjlBBrdhydpH7jHngmB76R7hnEeYl6cE0Mbu68K5a3LlqDvAvVKYgP8nri6IUT+gFb4B8APGnvM1iHy2Vp.uRD.0U45ETE77HlreVvs2id0RWZu5j5h2B2jIc5Mdeblw3iPE2mBeLAg6F3851k5HG5fyhq8roENqzjCmgM2ewztgmou7B3t4t68i8qxhB7H82IF7S3TfJBn7.kBr8y3gfHAgz.RHssnIn+hQD+.O5gfOujcGOgyIsX+D8hHOAFWZGkFK5ziv4TunoAfZtORf9nCEwJPfFDYHSgA.wfVPuhCc2DuSECTEGIzkTzp5jVTtql3MvmDgkGDv.gkGQXkTZkvJiHbkrBGPjAPbep7LU2sJwl7aj0UTYw4vPHPh1VA.n..YIU5PBUyqovqePOAm4nXYzH80ssuHlqa7mAtCX0f1Dlmp0nUbD.Z6d.uEnrdeDqBGAUD5C9J3RKCegVk8Etfn4pQbfjQ+lDEjxsvp4.PANMbYmAE5IdYtxM8JIIBTmTJNnI.CdpuFJGVZwpPF7eSoshBZbmQc3WGWO5HkTGhG5HUoh5MnOSS.y3lJUw3tcknbN7MvDCb9xJQWzCMl793fJQP6v4oyvFoqZTNpWgBMO8f2Cp4cg4jlo.IkBMIgf2HoFnkrD6HDm3Sz0FS0byr.U2wH7Z3mRNkp2hUm89ZMcWQnu8CoPhUgxV9R1i8Omz8XCl38XOvQBtP6PBOJPDASrybxsn9r1vf+nbbGwhJi0hbbqRkw77GsgUNsTghZPnHidWcqTlYz71a0jvycX.ctSpAKcsiW8i+5u8f83D.zpEEd4tGD4.AFUbN6.zlwvP8mpFcm4beUF1Uxx9QjPWHG5ja7VgKaa92JxY9I8YzeLCdl6S0p8yNYyBeGKY9e+saxM5d9TerESgorG+TpGzRq8wuB5g6Rh8joby2S1PvEoH+Cq.NjBi5N9XZtBqw9f1VJg+7X1B5CodTRTl9zucqGC.8jvFZD1oJV79+uxFa95avF20VAjX+gj29rVlcoanVXh1P8it+N8aq9YtCEvO++Sl9NX.SuhsNca+ue9djEewicw2Y9fV78y8x0oVN1kqSsb3x09DmPwycL+SCETyU0bfHFWu2273FJZ6xnSMqTNLk3CCsdtiS9i5BFVYZMbko0v6OsFt5zZ3ZSqgqOsFtw61P0NEaGKE9lNLXQql6YVl1xriktYC8OfVYMt3
      
      posted in Bug Reports
      HISEnbergH
      HISEnberg