Jump to content

Scripter for maximum polyphony (keep only most recent 4 notes)


Go to solution Solved by Atlas007,

Recommended Posts

I have a synth that gets stuck notes with polyphony >4, or when it receives too many midi notes in a short time.

Does anyone know of a script to limit simultaneous notes to a maximum of 4 in this case? Ideally with most recent note priority.

I tried to ChatGPT this but no luck! 😅

Link to comment
Share on other sites

ok...I had nothing better to do this morning..  here is a try at a scripter script for this, in case you want to avoid the environment, though David's simple environment solution should also work perfectly well....   its also an opportunity to share scripter tricks.  

I don't have a mac to test this, and it's a bit complicated so let me know if it actually works or not.  it could be enhanced to have a GUI slider for the MAX value also.

caveat...note that this is also kind of simplistic in that if you were to have two overlapping notes of the same pitch (which is unlikely anyway), then it would probably cut things off prematurely.  

 

var queue = [];
var offAlreadySent= [];
var MAX = 4;
var offEvent = new NoteOff;
offEvent.velocity = 100;

function HandleMIDI(event) {

    if(event instanceof NoteOn) {

        queue.push(event.pitch);

        // If queue bigger then MAX, then send NoteOff's early
        while (queue.length > MAX) {
            offEvent.pitch = queue.shift();
            offEvent.send();
            offAlreadySent.push(offEvent.pitch);
        }
    }

    else if (event instanceof NoteOff 
             || (event instanceof NoteOn && event.velocity < 1)) {
        
       // First check to see if we already sent NoteOff for this pitch
       for(let i=0; i<offAlreadySent.length; i++) {
           if(offAlreadySent[i] == event.pitch) {
	       // we already sent this NoteOff early, get out
	       offAlreadySent.splice(i,1);
	       return;
	   }
       }

       // Legit NoteOff so look for first matching pitch in queue to remove it
       for(let i=0; i<queue.length; i++) {
           if(queue[i] == event.pitch) {
	       queue.splice(i, 1);
	       break;
	   }
       }
    }

    event.send();
}

 

Edited by Dewdman42
  • Like 1
Link to comment
Share on other sites

alright, well I really should not have tried it without being able to test it myself, which unfortunately I cannot from the foreseeable future.  But anyway, maybe someone else may be able to figure out the exact tweak to get it working..  or just use the environment thing David showed

  • Like 1
Link to comment
Share on other sites

  • 2 weeks later...

Had a minute to tweak on that script above to see if I could get it working, here it is in case its of any interest......its actually working for me even as is originally, so I'm not sure why it didn't work before, but anyway here it is with a gui to set the amount of polyphony.  

The only thing I can figure is that its possible that the destination synth needs to see a bit of delay between the forced NoteOff and the next note that needs to use the voice..not really sure on that...would be interested to get it working though for the mental exercise...

So I added a 5ms delay here, but you can changed it to a different value, larger or smaller or zero or whatever, see the DROPDELAY variable at the top of the script.

var queue = [];
var offAlreadySent= [];
var offEvent = new NoteOff;
offEvent.velocity = 100;
const DROPDELAY = 5;   // ms

function HandleMIDI(event) {

    if(event instanceof NoteOn) {

        queue.push(event.pitch);

        // If queue bigger then MAX, then send NoteOff's early
        while (queue.length > GuiParameters.get(0)) {
            offEvent.pitch = queue.shift();
            offEvent.send();
            offAlreadySent.push(offEvent.pitch);
        }
        event.sendAfterMilliseconds(DROPDELAY);
        return;
    }

    else if (event instanceof NoteOff 
             || (event instanceof NoteOn && event.velocity < 1)) {
        
       // First check to see if we already sent NoteOff for this pitch
       for(let i=0; i<offAlreadySent.length; i++) {
           if(offAlreadySent[i] == event.pitch) {
               // we already sent this NoteOff early, get out
               offAlreadySent.splice(i,1);
               return;
           }
       }

       // Legit NoteOff so look for first matching pitch in queue to remove it
       for(let i=0; i<queue.length; i++) {
           if(queue[i] == event.pitch) {
               queue.splice(i, 1);
               break;
           }
       }
    }
   
    event.send();
}

/*********
 * GUI
 *********/
 
var PluginParameters = [{
    name: "Max Polyphony",
    type: "lin",
    minValue:  1,
    maxValue:  127,
    numberOfSteps: 126,
    defaultValue: 16,
    automation: true,
    hidden: false
}];

/**************************
 * More efficient GUI read
 **************************/
 
var GuiParameters = {
   data: [],
   set: function(id, val) {
       if(typeof id != "string") id = PluginParameters[id].name;
       this.data[id] = val;
   },
   get: function(id) {
       if(typeof id != "string") id = PluginParameters[id].name;
       if(this.data[id] == undefined) {
           this.data[id] = GetParameter(id);
       }
       return this.data[id];
   }
};
function ParameterChanged(id, val) {
   GuiParameters.set(id, val);
}

 

  • Like 3
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...