HISE Logo Forum
    • Categories
    • Register
    • Login

    Next HISE Developer Hang

    Scheduled Pinned Locked Moved General Questions
    49 Posts 11 Posters 1.7k 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.
    • clevername27C
      clevername27
      last edited by clevername27

      Choosing Time & Day

      • Doodle for voting on day and time. Note all time is GMT+5 GMT-5.

      Update: Dec 6, Friday, at 11 AM GMT+5 EST USA Time.


      Agenda Discussion

      Suggestion: Agendas should not depend on whether @Christoph-Hart can attend. Otherwise, the logistics are more complex; we should be self-sufficient. We can be flexible during the meetings, depending on the expertise available, so we can adapt if he is present.

      Post your agenda ideas as a response and discuss up until end of December 2 (GMT+5). I'll sort through them and announce the next morning.


      FAQ

      1. What is this?

      HISE Developer Hangs are the new skibidi. A 90-minute Zoom where HISE developers discuss matters of mutual interest. Topics might include Plugin Show & Tell, Technical How-To's, Group Voting on Suggestions to @Christoph-Hart, and Meta-Discussions on Future Meetings.

      2. What isn't this?

      Tech support. Please use this forum for that.

      3. Can anyone attend?

      Absolutely.

      4. Can I bring up a topic if it wasn't agreed upon?

      You can try. Despite any amount of previous organisation, the meetings will likely ebb and flow (and probably continue past the set end-time).

      5. Are the meetings recorded, in case I miss them?

      Yes. @d-healey will post them on his YouTube channel. Additionally, I will post a text-based summary on the forum.

      6. Is screen sharing supported (e.g. for demonstrating your plugin)?

      Yes, with high-resolution audio, if you use the Zoom app. (Think before you share.)

      7. What if I don't want to be recorded?

      Tell me in Zoom chat when you log into the Zoom.

      8. Where did this FAQ originate?

      Feel free to discuss in this thread, and we can revise as consensus emerges.

      9. That didn't answer the query.

      Not a question.

      griffinboyG Oli UllmannO HISEnbergH ustkU 5 Replies Last reply Reply Quote 4
      • griffinboyG
        griffinboy @clevername27
        last edited by griffinboy

        @clevername27

        Thanks, yes, broadcasters / AI are both things that I've been blindly stumbling through. I use both, but probably not with best practices! I wouldn't mind a discussion around these.

        At somepoint down the line I'd like to look in detail at c++ third party nodes, which wound probably require Christoph - I've been using these for quite a while now but the way I program my nodes doesn't fully agree with the way Hise works, it would be nice to some things laid bare, and see how Christoph would recommend working, especially to integrate more cleanly with hise's inbuilt systems.

        A super advanced topic I'd also like to tackle in the future is more integration of RT Neural. For instance I would like to have a neural network that can output more than just audio data - but rather can control other parameters. Or at the least can be integrated into a c++ node to control other parts of the script / generate data that can be stored into arrays. I have some rather grand plans, perhaps this is not the biggest concern for in terms of features for hise at present though : )

        clevername27C 1 Reply Last reply Reply Quote 2
        • Oli UllmannO
          Oli Ullmann @clevername27
          last edited by

          @clevername27
          I am not sure how many people with children will have time on the 6./7. because of Santa Claus...

          d.healeyD clevername27C 2 Replies Last reply Reply Quote 1
          • d.healeyD
            d.healey @Oli Ullmann
            last edited by

            @Oli-Ullmann Christmas in Europe πŸ˜€

            Libre Wave - Freedom respecting instruments and effects
            My Patreon - HISE tutorials
            YouTube Channel - Public HISE tutorials

            Oli UllmannO 1 Reply Last reply Reply Quote 1
            • Oli UllmannO
              Oli Ullmann @d.healey
              last edited by

              @d-healey
              In Germany we have Nikolaus (Santa Claus) on December, 6 and Christkind (Christmas) on December, 24. 😊

              Don't you have Nikolaus (Santa Claus) in England? πŸŽ…

              Matt_SFM d.healeyD 2 Replies Last reply Reply Quote 1
              • Matt_SFM
                Matt_SF @Oli Ullmann
                last edited by Matt_SF

                @Oli-Ullmann +1 for Nicklaus (I think it's a germanic thing (I live in France, but in Elsass))
                @griffinboy +1 for the broadcasters

                Develop branch
                Win10 & VS17 / Ventura & Xcode 14. 3

                1 Reply Last reply Reply Quote 2
                • d.healeyD
                  d.healey @Oli Ullmann
                  last edited by d.healey

                  @Oli-Ullmann said in Next HISE Developer Hang:

                  Don't you have Nikolaus (Santa Claus) in England?

                  Yes, we call him Father Christmas, he comes on December 24th. We don't have many other characters, no Krampus, no Christkind, we do get elves and reindeer though.

                  Libre Wave - Freedom respecting instruments and effects
                  My Patreon - HISE tutorials
                  YouTube Channel - Public HISE tutorials

                  1 Reply Last reply Reply Quote 2
                  • Oli UllmannO
                    Oli Ullmann @clevername27
                    last edited by

                    @clevername27
                    Another topic idea:

                    There is the great node β€œGranulator”. Unfortunately, at first glance there is no option for an envelope release. Perhaps a solution can be discussed or someone already has a solution in mind. :-)

                    I've seen this question asked here in the forum a few times.

                    clevername27C 2 Replies Last reply Reply Quote 1
                    • HISEnbergH
                      HISEnberg @clevername27
                      last edited by HISEnberg

                      @clevername27 Thank you for arranging this!

                      A few topic recommendations:

                      1. @ustk put together a great snippet for an audio buffer within scriptnode. I am still exploring for a way to create a ring buffer, so if someone has suggestions I am all ears.
                      2. Dynamic Component : I've seen Christoph has been slowly working on this behind the scenes but I would love to see any further updates on this. Essentially it is a way to add/destroy components to the UI dynamically. This ties in to any future updates he is working with.
                      3. Package Installers discussion. @clevername27 I would like to see more of this as well as @Lindon 's method.
                      4. Graphics: A rundown of what graphics processing are truly available in HISE (CSS, HISE LAF, Webview, OpenGL, etc.)
                      5. Loris: I am super interested in this library but haven't begun to use it so if someone has a project to share on this that would be great

                      I am also upvoting the broadcasters discussion. I use them but not to their full potential. The AI node would also be super cool. :)

                      Lastly, just a note. I have always struggled sharing HISE audio via ZOOM. I am not sure if this is a universal problem but it could prove to be an issue for the HISE meetup. Something to keep in mind.

                      d.healeyD griffinboyG clevername27C 4 Replies Last reply Reply Quote 1
                      • d.healeyD
                        d.healey @HISEnberg
                        last edited by

                        @HISEnberg said in Next HISE Developer Hang:

                        Loris: I am super interested in this library but haven't begun to use it so if someone has a project to share on this that would be great

                        Link Preview Image
                        GitHub - christophhart/loris-tools: A collection of sample analysis tools for HISE based on the Loris library

                        A collection of sample analysis tools for HISE based on the Loris library - christophhart/loris-tools

                        favicon

                        GitHub (github.com)

                        Libre Wave - Freedom respecting instruments and effects
                        My Patreon - HISE tutorials
                        YouTube Channel - Public HISE tutorials

                        1 Reply Last reply Reply Quote 1
                        • griffinboyG
                          griffinboy @HISEnberg
                          last edited by

                          @HISEnberg

                          Oh yes indeed, some laf stuff would be nice to look at, for the new css features and different ways of working.

                          Also btw about ringbuffers, if you need something in particular, I could probably help you out I've done lots of these before for delay lines and Lufs calculations

                          HISEnbergH 1 Reply Last reply Reply Quote 1
                          • HISEnbergH
                            HISEnberg @griffinboy
                            last edited by

                            @griffinboy Yes please if you have a C++ script you are willing to share that would be amazing!

                            griffinboyG 1 Reply Last reply Reply Quote 1
                            • griffinboyG
                              griffinboy @HISEnberg
                              last edited by griffinboy

                              @HISEnberg

                              I'll get back to you on this in a bit.

                              But if you want to get started immediately, I can give you my LUFS script. But I'll come up with a simpler example to give you in a bit. I've been meaning to improve my buffer stuff, infact it's one thing I wish to talk to with Christoph about... because it's possible to integrate directly with the audio buffers in hise, and c++ nodes so that the interface script can also talk to the same buffers, but I've not managed to completely get it right.

                              Anyway, Here's Lufs, it's a fairly old and awful script, and you won't be able to run this script but you can read it

                              #pragma once
                              #include <JuceHeader.h>
                              #include <limits>
                              #include <atomic>
                              #include <cmath>
                              #include "src/GlobalCables.h"
                              
                              #ifndef M_PI
                              #define M_PI 3.14159265358979323846
                              #endif
                              
                              namespace project
                              {
                                  using namespace juce;
                                  using namespace hise;
                                  using namespace scriptnode;
                              
                                  template <int NV> struct Lufs_In : public data::base
                                  {
                                      SNEX_NODE(Lufs_In);
                              
                                      struct MetadataClass
                                      {
                                          SN_NODE_ID("Lufs_In");
                                      };
                              
                                      static constexpr bool isModNode() { return true; }
                                      static constexpr bool isPolyphonic() { return NV > 1; }
                                      static constexpr bool hasTail() { return false; }
                                      static constexpr bool isSuspendedOnSilence() { return false; }
                                      static constexpr int getFixChannelAmount() { return 2; }
                              
                                      static constexpr int NumTables = 0;
                                      static constexpr int NumSliderPacks = 0;
                                      static constexpr int NumAudioFiles = 0;
                                      static constexpr int NumFilters = 0;
                                      static constexpr int NumDisplayBuffers = 0;
                              
                                      // Internal Parameters
                                      float sampleRate = 44100.0f;
                                      float blockSize = 512.0f;
                                      float lufsBlockSize = 400.0f; // Default to 400ms
                                      float overlap = 0.75f;        // 75% overlap
                                      ModValue modValue;
                              
                                      // LUFS calculation
                                      juce::AudioBuffer<float> filteredRingBuffer;
                                      size_t ringBufferWritePos = 0;
                                      size_t ringBufferSize = 0;
                                      size_t hopSize = 0;
                                      double runningSum = 0.0;
                              
                                      // JUCE IIR Filters
                                      std::array<juce::IIRFilter, 2> preFilters;
                                      std::array<juce::IIRFilter, 2> weightingFilters;
                              
                                      // LUFS result
                                      float currentLUFS = -100.0f;
                              
                                      // Reusable filtered buffer
                                      juce::AudioBuffer<float> filteredBuffer;
                              
                                      // Thread safety
                                      std::atomic<bool> parametersChanged{ false };
                                      juce::CriticalSection processLock;
                              
                                      void prepare(PrepareSpecs specs)
                                      {
                                          juce::ScopedLock sl(processLock);
                                          sampleRate = static_cast<float>(specs.sampleRate);
                                          blockSize = static_cast<float>(specs.blockSize);
                                          updateInternalState();
                                      }
                              
                                      void updateInternalState()
                                      {
                                          // Clamp and validate parameters
                                          lufsBlockSize = juce::jlimit(100.0f, 4000.0f, lufsBlockSize); // 100ms to 4000ms
                                          overlap = juce::jlimit(0.0001f, 0.9999f, overlap);            // 0.01% to 99.99%
                              
                                          // Calculate ring buffer size and ensure it's positive
                                          ringBufferSize = static_cast<size_t>(sampleRate * lufsBlockSize / 1000.0f);
                                          jassert(ringBufferSize > 0 && "ringBufferSize must be greater than 0");
                              
                                          hopSize = std::max(static_cast<size_t>(1), static_cast<size_t>(ringBufferSize * (1.0f - overlap)));
                                          filteredRingBuffer.setSize(2, static_cast<int>(ringBufferSize));
                                          ringBufferWritePos = 0;
                                          runningSum = 0.0;
                                          filteredBuffer.setSize(2, static_cast<int>(blockSize));
                              
                                          calculateFilterCoefficients();
                                          reset();
                                      }
                              
                                      void calculateFilterCoefficients()
                                      {
                                          const double epsilon = 1e-12; // Small value to prevent division by zero
                              
                                          // Pre-filter coefficients (as per your original code)
                                          const double db = 3.999843853973347;
                                          const double f0 = 1681.974450955533;
                                          const double Q = 0.7071752369554196;
                                          const double K = std::tan(M_PI * f0 / sampleRate);
                              
                                          const double Vh = std::pow(10.0, db / 20.0);
                                          const double Vb = std::pow(Vh, 0.4996667741545416);
                              
                                          const double denominator0 = 1.0 + K / Q + K * K + epsilon; // Added epsilon
                                          const double denominator1 = 2.0 * (K * K - 1.0) / denominator0;
                                          const double denominator2 = (1.0 - K / Q + K * K) / denominator0;
                                          const double numerator0 = (Vh + Vb * K / Q + K * K) / denominator0;
                                          const double numerator1 = 2.0 * (K * K - Vh) / denominator0;
                                          const double numerator2 = (Vh - Vb * K / Q + K * K) / denominator0;
                              
                                          // Validate coefficients
                                          jassert(!std::isnan(numerator0) && !std::isinf(numerator0));
                                          jassert(!std::isnan(numerator1) && !std::isinf(numerator1));
                                          jassert(!std::isnan(numerator2) && !std::isinf(numerator2));
                                          jassert(!std::isnan(denominator1) && !std::isinf(denominator1));
                                          jassert(!std::isnan(denominator2) && !std::isinf(denominator2));
                              
                                          juce::IIRCoefficients preCoeffs(numerator0, numerator1, numerator2,
                                              1.0, denominator1, denominator2);
                              
                                          // Weighting filter coefficients (as per your original code)
                                          const double f0_weighting = 38.13547087602444;
                                          const double Q_weighting = 0.5003270373238773;
                                          const double K_weighting = std::tan(M_PI * f0_weighting / sampleRate);
                              
                                          const double denominator0_weighting = 1.0 + K_weighting / Q_weighting + K_weighting * K_weighting + epsilon; // Added epsilon
                                          const double denominator1_weighting = 2.0 * (K_weighting * K_weighting - 1.0) / denominator0_weighting;
                                          const double denominator2_weighting = (1.0 - K_weighting / Q_weighting + K_weighting * K_weighting) / denominator0_weighting;
                              
                                          // Validate weighting coefficients
                                          jassert(!std::isnan(denominator0_weighting) && !std::isinf(denominator0_weighting));
                                          jassert(!std::isnan(denominator1_weighting) && !std::isinf(denominator1_weighting));
                                          jassert(!std::isnan(denominator2_weighting) && !std::isinf(denominator2_weighting));
                              
                                          juce::IIRCoefficients weightingCoeffs(1.0, -2.0, 1.0,
                                              1.0, denominator1_weighting, denominator2_weighting);
                              
                                          for (int ch = 0; ch < 2; ++ch)
                                          {
                                              preFilters[ch].setCoefficients(preCoeffs);
                                              weightingFilters[ch].setCoefficients(weightingCoeffs);
                                          }
                                      }
                              
                                      template <typename ProcessDataType>
                                      void process(ProcessDataType& data)
                                      {
                                          auto& fixData = data.template as<ProcessData<2>>();
                                          auto numSamples = fixData.getNumSamples();
                              
                                          if (numSamples == 0)
                                              return;
                              
                                          // Check if the block is silent
                                          bool isSilent = true;
                                          for (int ch = 0; ch < 2; ++ch)
                                          {
                                              auto channelData = fixData[ch];
                                              for (int i = 0; i < numSamples; ++i)
                                              {
                                                  if (channelData[i] > 0.0001f)
                                                  {
                                                      isSilent = false;
                                                      break;
                                                  }
                                              }
                                              if (!isSilent)
                                                  break;
                                          }
                              
                                          // If the block is silent, return early
                                          if (isSilent)
                                          {
                                              return;
                                          }
                              
                                          if (parametersChanged.exchange(false))
                                          {
                                              juce::ScopedLock sl(processLock);
                                              updateInternalState();
                                          }
                              
                                          juce::ScopedLock sl(processLock);
                              
                                          // Ensure the filteredBuffer is large enough
                                          if (filteredBuffer.getNumSamples() < numSamples)
                                              filteredBuffer.setSize(2, numSamples);
                              
                                          // Create AudioBlock objects for input and filtered data
                                          auto inputBlock = fixData.toAudioBlock();
                                          juce::AudioBuffer<float> filteredAudioBuffer(filteredBuffer);
                                          auto filteredBlock = juce::dsp::AudioBlock<float>(filteredAudioBuffer);
                              
                                          for (int ch = 0; ch < 2; ++ch)
                                          {
                                              // Copy input data to filteredBuffer
                                              juce::FloatVectorOperations::copy(filteredBlock.getChannelPointer(ch),
                                                  inputBlock.getChannelPointer(ch),
                                                  static_cast<int>(numSamples));
                              
                                              // Apply pre-filter
                                              preFilters[ch].processSamples(filteredBlock.getChannelPointer(ch), numSamples);
                              
                                              // Apply weighting filter
                                              weightingFilters[ch].processSamples(filteredBlock.getChannelPointer(ch), numSamples);
                                          }
                              
                                          // Store filtered samples in ring buffer and update LUFS
                                          for (size_t i = 0; i < numSamples; ++i)
                                          {
                                              double leftSample = static_cast<double>(filteredBlock.getSample(0, static_cast<int>(i)));
                                              double rightSample = static_cast<double>(filteredBlock.getSample(1, static_cast<int>(i)));
                              
                                              // Subtract the square of the oldest samples
                                              float oldLeftSample = filteredRingBuffer.getSample(0, static_cast<int>(ringBufferWritePos));
                                              float oldRightSample = filteredRingBuffer.getSample(1, static_cast<int>(ringBufferWritePos));
                                              runningSum -= static_cast<double>(oldLeftSample * oldLeftSample + oldRightSample * oldRightSample);
                              
                                              // Add the square of the new samples
                                              runningSum += leftSample * leftSample + rightSample * rightSample;
                              
                                              // Update ring buffer
                                              filteredRingBuffer.setSample(0, static_cast<int>(ringBufferWritePos), static_cast<float>(leftSample));
                                              filteredRingBuffer.setSample(1, static_cast<int>(ringBufferWritePos), static_cast<float>(rightSample));
                                              ringBufferWritePos = (ringBufferWritePos + 1) % ringBufferSize;
                              
                                              // Calculate LUFS when we've moved by hopSize or if hopSize is 0
                                              if (hopSize == 0 || ringBufferWritePos % hopSize == 0)
                                              {
                                                  calculateLUFS();
                                              }
                                          }
                                      }
                              
                                      void calculateLUFS()
                                      {
                                          jassert(ringBufferSize > 0 && "ringBufferSize must be greater than 0");
                              
                                          double meanSquared = runningSum / (2.0 * ringBufferSize);
                              
                                          if (meanSquared > 1e-12)
                                          {
                                              currentLUFS = static_cast<float>(-0.691 + 10.0 * std::log10(meanSquared));
                                              currentLUFS = std::clamp(currentLUFS, -100.0f, 0.0f);
                                          }
                                          else
                                          {
                                              currentLUFS = -100.0f;
                                          }
                              
                                          modValue.setModValue(currentLUFS + 2.96f);
                                      }
                              
                                      float getLUFS() const { return currentLUFS; }
                              
                                      void handleHiseEvent(HiseEvent& e) {}
                              
                                      void reset()
                                      {
                                          juce::ScopedLock sl(processLock);
                                          ringBufferWritePos = 0;
                                          runningSum = 0.0;
                                          filteredRingBuffer.clear();
                                          for (int ch = 0; ch < 2; ++ch)
                                          {
                                              preFilters[ch].reset();
                                              weightingFilters[ch].reset();
                                          }
                                          currentLUFS = -100.0f;
                                      }
                              
                                      template <typename T> void processFrame(T& data) {}
                              
                                      int handleModulation(double& value)
                                      {
                                          return modValue.getChangedValue(value);
                                      }
                              
                                      template <int P> void setParameter(double v)
                                      {
                                          if (P == 0)
                                          {
                                              lufsBlockSize = static_cast<float>(v);
                                              parametersChanged.store(true);
                                          }
                                          else if (P == 1)
                                          {
                                              overlap = static_cast<float>(v);
                                              parametersChanged.store(true);
                                          }
                                          reset();
                                      }
                              
                                      void createParameters(ParameterDataList& data)
                                      {
                                          {
                                              parameter::data p("Buffer Size (ms)", { 100.0, 4000.0 });
                                              registerCallback<0>(p);
                                              p.setDefaultValue(2800.0);
                                              data.add(std::move(p));
                                          }
                                          {
                                              parameter::data p("Overlap", { 0.0001, 0.9999 });
                                              registerCallback<1>(p);
                                              p.setDefaultValue(0.99);
                                              data.add(std::move(p));
                                          }
                                      }
                                  };
                              }
                              
                              1 Reply Last reply Reply Quote 3
                              • ustkU
                                ustk @clevername27
                                last edited by ustk

                                @clevername27

                                DISCUSSIONS:

                                • Advanced graphics rendering, past the poorly supported OpenGL shader on mac, what comes next?
                                • Issue reports and pull-requests aren't fixed/merged as fast as our ego requests to live in peace, "yeah I want that thing fixed before I even formulate a thought about it..." ☺
                                • SNEX issues/instabilities/console improvements... Not adding new functionalities though, just a more reliable environment for sketching more efficiently

                                About @Christoph-Hart attending the meeting or not, I think it is a necessity though. Many of the questions that will be raised can be answered quickly without us discussing the piece of meet endlessly. Not speaking that bunch of questions might not be even discussable without him, like, "where does your love for Comic Sans MS come from..."

                                Can't help pressing F5 in the forum...

                                d.healeyD clevername27C 2 Replies Last reply Reply Quote 1
                                • d.healeyD
                                  d.healey @ustk
                                  last edited by

                                  @ustk said in Next HISE Developer Hang:

                                  I think it is a necessity though.

                                  I agree, at least for all the topics mentioned here.

                                  Maybe it would be better to do a show and tell type thing since Christoph can't attend.

                                  Libre Wave - Freedom respecting instruments and effects
                                  My Patreon - HISE tutorials
                                  YouTube Channel - Public HISE tutorials

                                  clevername27C 1 Reply Last reply Reply Quote 1
                                  • clevername27C
                                    clevername27 @Oli Ullmann
                                    last edited by clevername27

                                    This post is deleted!
                                    1 Reply Last reply Reply Quote 1
                                    • clevername27C
                                      clevername27 @griffinboy
                                      last edited by clevername27

                                      @griffinboy said in Next HISE Developer Hang:

                                      broadcasters / AI

                                      I can help with the theory on publish and subscribe (broadcasters) and AI. If you tell me what you're looking to do, I can prepare something for the Hang.

                                      1 Reply Last reply Reply Quote 0
                                      • clevername27C
                                        clevername27 @Oli Ullmann
                                        last edited by

                                        @Oli-Ullmann Is there another day you suggest I replace it with?

                                        Oli UllmannO 1 Reply Last reply Reply Quote 0
                                        • clevername27C
                                          clevername27 @Oli Ullmann
                                          last edited by

                                          @Oli-Ullmann I'm thinking one thing we could do is, as a group, create a list of technical questions for @Christoph-Hart that haven't been answered on the forum. Given the specificity and focus of your question, perhaps that would address it?

                                          1 Reply Last reply Reply Quote 2
                                          • clevername27C
                                            clevername27 @HISEnberg
                                            last edited by

                                            @HISEnberg I'm happy to help you one-on-one with package installers and HISE graphics over Zoom. We could also trouble-shoot the audio. DM me if interested.

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

                                            57

                                            Online

                                            1.7k

                                            Users

                                            11.7k

                                            Topics

                                            102.2k

                                            Posts