HISE Logo Forum
    • Categories
    • Register
    • Login

    Basic Random Round Robin Script

    Scheduled Pinned Locked Moved Scripting
    8 Posts 3 Posters 714 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.
    • d.healeyD
      d.healey
      last edited by d.healey

      Here's a very simple random round robin script. It works with up to 50 RR groups but if you manage to exceed that limit it's easy to modify to handle more. I'm uploading an explanation/tutorial video of me writing this for my Patreon supporters.

      Content.setWidth(600);
      Content.setHeight(50);
      
      const var Sampler1 = Synth.getChildSynth("Sampler1");
      Sampler1.asSampler().enableRoundRobin(false);
      
      const var knbGroups = Content.addKnob("knbGroups", 0, 0);
      knbGroups.set("text", "RR Groups");
      knbGroups.setRange(1, 50, 1);
      
      function onNoteOn()
      {
          local groupNum = Math.randInt(1, knbGroups.getValue()+1);   
          Sampler1.asSampler().setActiveGroup(groupNum);
      }
      function onNoteOff()
      {
      	
      }
      function onController()
      {
      	
      }
      function onTimer()
      {
      	
      }
      function onControl(number, value)
      {
      	
      }
      

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

      1 Reply Last reply Reply Quote 0
      • d.healeyD
        d.healey
        last edited by

        Anyone know if it's possible to enable more than one group at a time? I'm aware that enabling xfade mode will enable all groups, but how to enable a subset?

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

        1 Reply Last reply Reply Quote 0
        • Christoph HartC
          Christoph Hart
          last edited by Christoph Hart

          Ah, actually it's not possible - there's only Sampler.setActiveGroup() which takes an int and deactivates all others.

          I think the reason why I didn't implement it is because I never needed to play more than one RR group - for all scenarios that might want to do it, I just duplicated the samplers.

          1 Reply Last reply Reply Quote 0
          • Christoph HartC
            Christoph Hart
            last edited by

            By the way, a nice way of avoiding repeating RR groups is to use a while loop to get a "really" new value:

            
            reg lastIndex = -1;
            reg numGroups = 3;
            
            inline function nextWithoutRepeat()
            {
                // We have to catch this case, otherwise we'll
                // be stuck in an endless loop later
                if(numGroups == 0)
                    return 0;
            
                local newIndex = Math.randInt(0, numGroups);
                
                while(newIndex == lastIndex)
                    newIndex = Math.randInt(0, numGroups);
            
                lastIndex = newIndex;
                return newIndex;
            }
            
            inline function next()
            {
                return Math.randInt(0, numGroups);
            }
            
            Console.print("Watch out for repeated groups");
            Console.print(next());
            Console.print(next());
            Console.print(next());
            Console.print(next());
            Console.print(next());
            Console.print(next());
            Console.print(next());
            Console.print(next());
            Console.print(next());
            Console.print(next());
            Console.print(next());
            
            Console.print("Now they're gone");
            Console.print(nextWithoutRepeat());
            Console.print(nextWithoutRepeat());
            Console.print(nextWithoutRepeat());
            Console.print(nextWithoutRepeat());
            Console.print(nextWithoutRepeat());
            Console.print(nextWithoutRepeat());
            Console.print(nextWithoutRepeat());
            Console.print(nextWithoutRepeat());
            Console.print(nextWithoutRepeat());
            Console.print(nextWithoutRepeat());
            Console.print(nextWithoutRepeat());
            Console.print(nextWithoutRepeat());
            

            Of course this might result in a theoretically endless runtime (if the RNG always spits out the same number, you're lost), but it really helps making the sound more natural if you're using less than 4 RR groups.

            1 Reply Last reply Reply Quote 2
            • ustkU
              ustk
              last edited by

              Is it possible to get the number of RR in a map?
              because if it differs from one to another, it is a bit tricky to run a random smoothly...

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

              1 Reply Last reply Reply Quote 0
              • Christoph HartC
                Christoph Hart
                last edited by Christoph Hart

                Yeah sure, it's a sampler property that you can query using getAttribute(7) - sorry for the magic number, but I still haven't figured out a smart way to avoid this for samplers since the constant ID slots are used for the sample properties.

                Anyways, the only missing piece to make this an automatic group randomizer without the requirement of carrying a knob around that sets the amount of groups is to find a place where to call this method. The brute force method would be to have a timer that periodically checks the amount, but it's ugly and might lead to glitches between loading samplemaps.

                I recommend using the loading callback of a (hidden) script panel which will be fired after each preloading task, which happens everytime you swap a samplemap:

                // This will hold the current RR group amount
                reg numRRGroups = 0;
                
                // Create a default reference to a sampler somehow
                const var Sampler1 = Synth.getChildSynth("Sampler1");
                 
                // in a perfect world this would not be a UI element but a headless object like the thing
                // you get by Engine.createTimerObject(), but since the primary use case of this is to display some
                // sort of loading indication it makes sense to couple it to a panel.
                const var RRUpdater = Content.addPanel("RRUpdater", 0, 0);
                
                // You are ugly and we don't want to see you.
                RRUpdater.set("visible", false);
                
                // We can give the panel a function that is executed whenever the preload state changes, 
                // so we'll use this event to update the RR groups.
                RRUpdater.setLoadingCallback(function(isPreloading)
                {
                    // the flag indicates the start / stop event and since we want 
                    // to wait until everything is done, we'll use the stop event.
                    if(!isPreloading)
                    {
                        numRRGroups = Sampler1.getAttribute(7);
                        Console.print(numRRGroups);
                    }
                });
                1 Reply Last reply Reply Quote 0
                • ustkU
                  ustk
                  last edited by

                  Ok thanks 😉
                  Or I can do it directly in the function that calls for the new samplemap, no?
                  Why going on the wild side of using a hidden panel instead?

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

                  1 Reply Last reply Reply Quote 0
                  • Christoph HartC
                    Christoph Hart
                    last edited by

                    Because the loading of sample maps is asynchronous: the call to Sampler.loadSampleMap() doesn't do anything heavyweight, it just posts a notification to the worker thread which kills all notes gracefully, suspends the audio rendering and then performs the loading & preloading until everything is done and then reenables the audio rendering for the ultimate smooth swapping experience.

                    Since this can take a few seconds for big sample sets, having the script engine in a busy-wait state is not an option (in fact, the time-out protection would fire). Hence you need to jump through the hidden Panel hoop.

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

                    15

                    Online

                    1.7k

                    Users

                    11.7k

                    Topics

                    102.3k

                    Posts