Jump to content

Conditional Delays Using Scripter?


EoinF

Recommended Posts

Hello from a first-time poster,

 

I'm wondering if the following is possible using Logic's Scripter? Hopefully some experienced users of Scripter would be able give some advice - of which I would be extremely grateful.

 

I'm looking for a script that can delay sending MIDI notes (note on, note release, and velocity) to an instrument based on the value of a CC:

 

For instance, if the value of CC11 is between 11 and 20, delay the note by 250ms, If the value of CC11 is between 21 and 30 delay the note by 100ms, and other similar conditions.

 

Another slightly more complex conditional message, would include an 'and' statement:

 

For instance, if CC11 is between 31 and 40, and note velocity is between 1 and 64, delay the note by 200ms, or if CC11 is between 31 and 40, and note velocity is between 65 and 127, delay the note by 100ms.

 

I'm hoping something like this could be possible, as it could potentially save me an awful lot of time on projects.

 

If anyone has done something like this before, or feels they know how to, I would be extremely grateful to hear from you, and please do let me know if any more information is required.

 

Many thanks,

Eoin

Link to comment
Share on other sites

It's possible, both in Scripter and in the Environment, depending on the type of setup and conditions, although proper processing of NoteOffs is not entirely trivial.

 

However, it is unclear what Eoin actually wants.

 

Have you tried to implement it, but got stuck somewhere in the process and need advice to solve specific problems ? Then ask away, with specifics.

 

Or did you just dream this up in your armchair and want someone to code it for you ?

Link to comment
Share on other sites

Atlas007,

 

Thanks for your reply. Similar to yourself, I feel it should be possible, although I don’t know enough about Scripter to say for sure. I do hope you’re right!

 

fuzzfilth,

 

Thank you for your reply. I have tried to research how to implement something like this, but haven’t been able to find much information relating to what I am trying to do, and my experience with Scripter is very limited, so it is not something I would be likely to work out on my own.

 

I would be very appreciative if someone could point me in the direction of somewhere I could learn about similar processes, or share a commonly available and easily repeatable string of code that I could try to implement myself.

 

However, if the process is not entirely trivial like you say, I would be very happy to pay someone to write a script for me - I definitely do not want someone to do a not-insubstantial amount of work for no reward.

 

Here is a more specific version of what I am trying to do (leaving out the velocity sensitive information for now):

 

I am using articulation sets with instruments that have different note onset times for each articulation (say 50ms for staccato, 100ms for legato, etc.). The articulation sets change articulations on each instrument using values of a CC. I want the value of this CC to also control the value of a specified delay for each note sent to the instrument, so that when I change articulations on notes in the piano roll, the timing of each note onset does not become a problem, and I do not have to manually nudge each note into time. Hopefully what I have just said makes sense.

 

I am not sure that the NoteOff data needs to be treated in the way I had mentioned in my original post here (that the NoteOff needs to be treated with the same delay as the NoteOn of same note, regardless of what CC change has been made between NoteOn and NoteOff) - I thought, perhaps naively, this option would have been the easier option to implement, but if it’s easier to let the note releases follow the delay time of any CC change that happens between NoteOn and NoteOff, this may well be a preferable option. I will consider/test this with situations that may arise.

 

Thanks again for your reply,

Eoin

Link to comment
Share on other sites

Atlas007, yes, I’m pretty sure it sends the message contained in the ArtID either at the same instant or just before sending the NoteOn. In my experience it is a lot quicker to use than key switches or drawing in CC data, and is more reliable/foolproof.
Link to comment
Share on other sites

Regarding NoteOff's yes that complicates things and it will not be a trivial script to write, so you'll have to learn javascript I guess if you want to do something a little more sophisticated. Scripter doesn't know anything about duration of notes. It can only detect a NoteOn coming through and a NoteOff coming through. So you can try to match the NoteOff delay with the NoteOn... For example something simple maybe:

 

var ccnum = 11;
var lastDelay = 0;

var notes = new Array(128);
for(var i=0;i<128;i++) {
   notes[i] = 0;
}

function HandleMIDI(event) {
   if(event instanceof ControlChange && event.number == ccnum) {
       lastDelay = event.value;
       return;
   }

   if (event instanceof NoteOn) {
       notes[event.pitch] = lastDelay;
       event.sendAfterMilliseconds(lastDelay);
       return;
   }
   else if(event instanceof NoteOff || (event instanceof NoteOn && event.velocity == 0)) {
       event.sendAfterMilliseconds(notes[event.pitch]);
       notes[event.pitch] = 0;
       return;
   }
       
   event.send();
}
Edited by Dewdman42
Link to comment
Share on other sites

You still have to detect NoteOn and NoteOff separately in order to handle them slightly differently. Look closely at the code to see the difference. The script has to keep track of what the delay was for the NoteOn coming through and then use that same amount of delay for its matching NoteOff when it finally comes through.
Link to comment
Share on other sites

Hello Dewdman42,

 

Thank you so much for taking the time to help me with this - I really appreciate it.

 

I have tried both of your scripts and they are both working as expected (if my understanding of them is correct).

 

Am I right in saying each of these scripts will create a delay where the the delay time in milliseconds is equal to the event.value (between 0 and 127)? I tried adding a multiplier (event.value * 10) on line 6 of your first example and it seems this is the case.

 

I'm hoping that the event.value can change the delay time to specified values that are independent of the event.value itself (that is, not a multiple of the event.value in any way), as this event.value will also be used to change the articulation.

 

It will have to be set up as a table of specified numbers. For example:

 

event.value 0 to 9 = 200ms delay

event.value 10 to 19 = 100ms delay

event.value 20 to 29 = 250ms delay etc.

 

I've tried editing your original script to do something like this. I am very new to this language, so perhaps I am not doing everything correctly, or in the most efficient way, but hopefully what I've done here makes sense.

 

var ccnum = 11;
var lastDelay = 0;
delaytime1 = 1000;
delaytime2 = 2000;

function HandleMIDI(event) {
   if(event instanceof ControlChange && event.number == ccnum && event.value >= 0 && event.value <= 9) {
       lastDelay = delaytime1; 
       return;
   }
   else if(event instanceof ControlChange && event.number == ccnum && event.value >= 10 && event.value <= 19) {
       lastDelay = delaytime2; 
       return;
       }
       
   event.sendAfterMilliseconds(lastDelay);
}

 

It seems to be doing what I want it to do (I'm going to forget about the separate treatment of NoteOffs for now). I'll spend some more time with this tomorrow and actually input what I hope to do with it and give it an initial test.

 

One question - does this script delay all MIDI messages (modulation, pitch bend, etc.) or just notes?

 

Thank you again for your help,

Eoin

Link to comment
Share on other sites

what I would do if I were you is to use an array that maps the cc value to the desired delay. Then you can assign all 128 cc values to any delay you want.

 

So something like this:

 

var ccnum = 11;

var delayMap = [200,200,200,200,200,200,200,200,200,200,100,100,100,100,100,100,100,
               100,100,100,250,250,250,250,250,250,250,250,250,250,0,0,0,0,0,0,0,0,
               0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
               0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0];
                                               
var lastDelay = 0;
var notes = new Array(128);
for(var i=0;i<128;i++) {
   notes[i] = 0;
}

function HandleMIDI(event) {
   if(event instanceof ControlChange && event.number == ccnum) {
       lastDelay = delayMap[event.value]
       return;
   }

   if (event instanceof NoteOn) {
       notes[event.pitch] = lastDelay;
       event.sendAfterMilliseconds(lastDelay);
       return;
   }
   else if(event instanceof NoteOff 
           || (event instanceof NoteOn && event.velocity == 0)) {
       event.sendAfterMilliseconds(notes[event.pitch]);
       notes[event.pitch] = 0;
       return;
   }
       
   event.send();
}

 

The first script is very simplistic, it delays all events for whatever the CC currently is and doesn't try to match the NoteOn to the NoteOff delay time. The second one makes sure the NoteOff is delayed by the same amount as NoteOn.

 

Anyway, hopefully that is enough info to get you started. Check out endless javascript resources on the net and tweak the script as needed!

Edited by Dewdman42
Link to comment
Share on other sites

Thank you so much for your help! You definitely have given me enough info to get started, and then some! I'll spend some more time learning the language and working on this script, and report back here when I have made some progress (or more likely when I come to a point where I haven't a clue what I am doing!).

 

Eoin

Link to comment
Share on other sites

With thanks to Dewdman42 I'm making some good progress with this script. I decided to go with the original method he suggested (and not the array two posts above) as I feel it would be easier to make quick changes to the delay times on the script if I need to in the future. Here it is as it stands, including some script that is not working towards the end.

 

 /* Editable Delay Times */
LegatoStartSlow = 0;
LegatoStartMedium = 100;
LegatoStartFast = 200;
LegatoSlow = 0;
LegatoMedium = 100;
LegatoFast = 200;
Spiccato = 250;
Staccatissimo = 245;
Staccato = 240;
Sfz = 240;
Pizzicato = 250;
BartokSnap = 250;
ColLegno = 250;
Trills = 250;
Harmonics = 200;
Tremolo = 200;
MeasuredTremolo = 200;
Marcato = 250;
MarcatoOverlay = 250;

/* Keyswitch CC */
var ccnum = 58;
var lastDelay = 0;

function HandleMIDI(event) {
   if(event instanceof ControlChange && event.number == ccnum && event.value >= 11 && event.value <= 15) {
       lastDelay = Spiccato; 
       return;
   }
   else if(event instanceof ControlChange && event.number == ccnum && event.value >= 16 && event.value <= 20) {
       lastDelay = Staccatissimo; 
       return;
   }
   else if(event instanceof ControlChange && event.number == ccnum && event.value >= 21 && event.value <= 25) {
       lastDelay = Staccato; 
       return;
   }
   else if(event instanceof ControlChange && event.number == ccnum && event.value >= 26 && event.value <= 30) {
       lastDelay = Sfz; 
       return;
   }
   else if(event instanceof ControlChange && event.number == ccnum && event.value >= 31 && event.value <= 35) {
       lastDelay = Pizzicato; 
       return;
   }
   else if(event instanceof ControlChange && event.number == ccnum && event.value >= 36 && event.value <= 40) {
       lastDelay = BartokSnap; 
       return;
   }
   else if(event instanceof ControlChange && event.number == ccnum && event.value >= 41 && event.value <= 45) {
       lastDelay = ColLegno; 
       return;
   }
   else if(event instanceof ControlChange && event.number == ccnum && event.value >= 46 && event.value <= 50) {
       lastDelay = Trills; 
       return;
   }
   else if(event instanceof ControlChange && event.number == ccnum && event.value >= 51 && event.value <= 55) {
       lastDelay = Harmonics; 
       return;
   }
   else if(event instanceof ControlChange && event.number == ccnum && event.value >= 56 && event.value <= 60) {
       lastDelay = Tremolo; 
       return;
   }
   else if(event instanceof ControlChange && event.number == ccnum && event.value >= 61 && event.value <= 65) {
       lastDelay = MeasuredTremolo; 
       return;
   }
   else if(event instanceof ControlChange && event.number == ccnum && event.value >= 66 && event.value <= 70) {
       lastDelay = Marcato; 
       return;
   }
   else if(event instanceof ControlChange && event.number == ccnum && event.value >= 71 && event.value <= 75) {
       lastDelay = MarcatoOverlay; 
       return;
   }
   
   /* Not Yet Working */
   else if(event instanceof NoteOn && event.velocity > 0 && event.velocity <= 64 && event instanceof ControlChange && event.number == ccnum && event.value >= 6 && event.value <= 8) {
       lastDelay = LegatoStartSlow; 
       return;
       }
       
   event.sendAfterMilliseconds(lastDelay);
}

 

Everything receiving just a cc event.value to specify the delay time seems to be working as expected, but I have not yet figured out how to specify a delay time for articulations that require a cc event.value and NoteOn velocity. I have written an attempt at this towards the end of the script labelled "Not Yet Working".

 

In the case of the attempt above, the delay time for LegatoStartSlow should be used if (and only if) both the cc event.value is between 6 and 8, and the NoteOn velocity is between 1 and 64. There will eventually be more cases that will use the same event.value range, but with different velocities, and another few cases that will use the same NoteOn velocity range but with different event.value ranges. The NoteOn velocity should not affect the delay time of the articulations that require only cc event.value ranges (the working cases above). Hopefully all of this makes sense.

 

In my attempt, I have tested each part of it separately...

 

    if(event instanceof NoteOn && event.velocity > 0 && event.velocity <= 64) {
       lastDelay = LegatoStartSlow; 
       return;
       }
       
   event.sendAfterMilliseconds(lastDelay);
}

and

 

    if(event instanceof ControlChange && event.number == ccnum && event.value >= 6 && event.value <= 8) {
       lastDelay = LegatoStartSlow; 
       return;
       }
       
   event.sendAfterMilliseconds(lastDelay);
}

 

...and alone they work as expected, but I have not been able to figure out how to combine the two so that they work together. As it stands the code labelled "Not Yet Working" has no effect on the output (and yes, I have tested it giving a value other than zero for LegatoStartSlow!).

 

Any help with this problem would be greatly appreciated.

 

Thanks,

Eoin

Link to comment
Share on other sites

Now that I see what you're trying to do, correct for articulation latency... You might want to consider using articulationID instead of a CC in front of the event. But if you're using an articulationSet to send Keyswitches, then no you can't do that because the articulationSet will strip off the articulationID when it sends the key switch.

 

As far as combining the two aspects, what you should do is rename the lastDelay variable to lastCC, then determine the delay to use later when the Note comes in..

 


/* Editable Delay Times */
LegatoStartSlow = 0;
LegatoStartMedium = 100;
LegatoStartFast = 200;
LegatoSlow = 0;
LegatoMedium = 100;
LegatoFast = 200;
Spiccato = 250;
Staccatissimo = 245;
Staccato = 240;
Sfz = 240;
Pizzicato = 250;
BartokSnap = 250;
ColLegno = 250;
Trills = 250;
Harmonics = 200;
Tremolo = 200;
MeasuredTremolo = 200;
Marcato = 250;
MarcatoOverlay = 250;

/* Keyswitch CC */
var ccnum = 58;
var lastCC = 0;

function HandleMIDI(event) {
   if(event instanceof ControlChange && event.number == ccnum) {
       lastCC = event.value;
       return;
   }
   
   if(event instanceof NoteOn) {
       var delay = 0;
       if(lastCC >=11 && lastCC <=15) {
           if(event.velocity>=1 && event.velocity <=64) {
               delay = Spiccato;
           }
           else {
               delay = BiggerSpiccato;
           }
       }
       else if(lastCC >= 16 && lastCC <= 20) {
           if(event.velocity >=1 && event.velocity <=64) {
               delay = SomeOtherAmount;
           }
           else {
               delay = AnotherBiggerDelay;
           }
       }
       /*
          .
          .
          .  More conditions here
          .
          .
       */
       event.sendAfterMilliseconds(delay);
   }
}
Link to comment
Share on other sites

another comment. it sounds like you are trying to do latency compensation for different articulations. So you will ultimately use a negative track delay to bring them all back forward again. That means you need to delay your NoteOff's by the longest-used delay amount, so that with the negative track delay they will be NoteOff when you intended them to be. Hope that makes sense.
Link to comment
Share on other sites

Hello Dewdman22,

 

Yes, this is intended to correct for articulation latency (in this case Cinematic Studio Strings). I am using articulation sets and these are set up to send the information required to switch articulations using CC58. I do intend to use a negative track delay (probably ~300ms).

 

I have thought about the separate treatment of NoteOffs, and what you have suggested is what I had originally hoped for, although I thought that perhaps this could cause more trouble than it is worth - If two notes are supposed to be non-slurred long notes (not overlapping on piano roll), this might cause the instrument to think that they are in fact overlapping, and trigger a transition sample. I imagine adjusting for this on piano roll could be tedious, and it would probably be easier to make adjustments to the note ends at the ends of phrases where necessary (besides, these often need to be adjusted anyway, as the release trigger samples for long notes in CSS are not super distinct - I believe they are designed to naturally trail off).

 

I have tried implementing what you have suggested for legato transitions, and the delay is working as it should, however it is only letting NoteOns through to the instrument, so articulations are not switched. NoteOffs and modulation data is also lost. Here is the code.

 

/* Editable Delay Times */
LegatoStartSlow = 0;
LegatoStartMedium = 500;
LegatoStartFast = 1000;
LegatoSlow = 1500;
LegatoMedium = 2000;
LegatoFast = 2500;
Spiccato = 250;
Staccatissimo = 245;
Staccato = 240;
Sfz = 240;
Pizzicato = 250;
BartokSnap = 250;
ColLegno = 250;
Trills = 250;
Harmonics = 200;
Tremolo = 200;
MeasuredTremolo = 200;
Marcato = 250;
MarcatoOverlay = 250;

/* Keyswitch CC */
var ccnum = 58;
var lastCC = 0;
var delay = 0;

function HandleMIDI(event) {
   if(event instanceof ControlChange && event.number == ccnum) {
       lastCC = event.value;
       return;
   }
   
   if(event instanceof NoteOn) {
       if(lastCC >=6 && lastCC <=8) {
           if(event.velocity >=1 && event.velocity <=64) {
               delay = LegatoStartSlow;
           }
           else if(event.velocity >=65 && event.velocity <=100) {
               delay = LegatoStartMedium;
           }
           else if(event.velocity >=101 && event.velocity <=127) {
               delay = LegatoStartFast;
           }
       }
       else if(lastCC >= 9 && lastCC <= 10) {
           if(event.velocity >=1 && event.velocity <=64) {
               delay = LegatoSlow;
           }
           else if(event.velocity >=65 && event.velocity <=100) {
               delay = LegatoMedium;
           }
           else if(event.velocity >=101 && event.velocity <=127) {
               delay = LegatoFast;
           }
       }
       /*
          .
          .
          .  More conditions here
          .
          .
       */
       event.trace();
       event.sendAfterMilliseconds(delay);
   }
}

 

And here is the trace for a couple of notes, each with a different articulation selected and some modulation drawn in.

 

Before script:

[ControlChange channel:1 number:1 [Modulation] value:0]

[ControlChange channel:1 number:13 [Effect #2 MSB] value:127]

[NoteOn channel:1 pitch:55 [G2] velocity:110]

[ControlChange channel:1 number:1 [Modulation] value:0]

[ControlChange channel:1 number:1 [Modulation] value:1]

[ControlChange channel:1 number:1 [Modulation] value:2]

[ControlChange channel:1 number:1 [Modulation] value:3]

[ControlChange channel:1 number:1 [Modulation] value:4]

[ControlChange channel:1 number:1 [Modulation] value:5]

[ControlChange channel:1 number:1 [Modulation] value:6]

[NoteOff channel:1 pitch:55 [G2] velocity:64]

[ControlChange channel:1 number:58 [#26 LSB] value:36]

[NoteOn channel:1 pitch:56 [G#2] velocity:110]

[ControlChange channel:1 number:58 [#26 LSB] value:0]

[ControlChange channel:1 number:1 [Modulation] value:7]

[ControlChange channel:1 number:1 [Modulation] value:8]

[ControlChange channel:1 number:1 [Modulation] value:9]

[ControlChange channel:1 number:1 [Modulation] value:10]

[ControlChange channel:1 number:1 [Modulation] value:11]

[ControlChange channel:1 number:1 [Modulation] value:12]

[ControlChange channel:1 number:1 [Modulation] value:13]

[ControlChange channel:1 number:1 [Modulation] value:14]

[NoteOff channel:1 pitch:56 [G#2] velocity:64]

[ControlChange channel:1 number:58 [#26 LSB] value:41]

[NoteOn channel:1 pitch:57 [A2] velocity:110]

[ControlChange channel:1 number:58 [#26 LSB] value:0]

[ControlChange channel:1 number:1 [Modulation] value:15]

[ControlChange channel:1 number:1 [Modulation] value:16]

[ControlChange channel:1 number:1 [Modulation] value:17]

[ControlChange channel:1 number:1 [Modulation] value:18]

[ControlChange channel:1 number:1 [Modulation] value:19]

[ControlChange channel:1 number:1 [Modulation] value:20]

[ControlChange channel:1 number:1 [Modulation] value:21]

[ControlChange channel:1 number:1 [Modulation] value:22]

[NoteOff channel:1 pitch:57 [A2] velocity:64]

 

...and after script:

[NoteOn channel:1 pitch:55 [G2] velocity:110]

[NoteOn channel:1 pitch:56 [G#2] velocity:110]

[NoteOn channel:1 pitch:57 [A2] velocity:110]

 

As you can see, only the NoteOns are retained after passing through the script, so this is all the information the instrument receives. I tried this with the last version of this script I had worked on and all data was passing through unaffected apart from the CC58 values that were specified in the script (They passed through but were given a value of 0) - all other values for CC58 passed through it unaffected. I'm guessing I'm probably missing something simple in each script that causes this behaviour - although it is definitely not simple to me!

 

I hope I'll be able to get this up and running quite easily once this problem is solved, and then I can begin testing it and working on the delay times so that everything plays back tight to the click with minimal adjustments on piano roll. I hope eventually to do a version for every instrument in CSS, CSSS, CSB (and hopefully soon CSW/CSP?) including the necessary articulation sets, and would be very happy to post links to everything here if people are interested. The aim of this project is to allow MIDI imported from a notation program such as Sibelius to be relatively quickly turned into a tight mockup without spending lots of time nudging notes around on the piano roll. I may eventually try to create a sound set in Sibelius that will automatically select the required articulation when imported into Logic.

 

Thanks again,

Eoin

Link to comment
Share on other sites

you might want to check out something called "Thanos". You can read about other users with this exact sample library trying to deal with the problem their own way. Look for a guy there named "NaomL" who authored that script, but I'm not sure how to obtain it. PM him to find out.

 

https://vi-control.net/community/threads/how-do-people-deal-with-css-delay.83142/page-2

 

I'll try to answer some of your questions anyway...

Link to comment
Share on other sites

Hello Dewdman22,

 

Yes, this is intended to correct for articulation latency (in this case Cinematic Studio Strings). I am using articulation sets and these are set up to send the information required to switch articulations using CC58. I do intend to use a negative track delay (probably ~300ms).

 

Since the articulationSet is sending CC58, that means midi events will have articulationID stripped off before hitting your script. So you can't use articulationID. Using CC58 is the right way, its giving you the same info. every time CC58 comes through, just set the lastCC value, and any noteOn that comes through will assume its that articulation.

 

I have thought about the separate treatment of NoteOffs, and what you have suggested is what I had originally hoped for, although I thought that perhaps this could cause more trouble than it is worth - If two notes are supposed to be non-slurred long notes (not overlapping on piano roll), this might cause the instrument to think that they are in fact overlapping, and trigger a transition sample. I imagine adjusting for this on piano roll could be tedious, and it would probably be easier to make adjustments to the note ends at the ends of phrases where necessary (besides, these often need to be adjusted anyway, as the release trigger samples for long notes in CSS are not super distinct - I believe they are designed to naturally trail off).

 

Well actually if you think about it, you want the NoteOff to happen exactly on time. You are only using the delay and negative track delay to compensate for a slow attack on the samples. Some are more then others, they are inconsistent. So in order to make them so that they sound on the grid, you use the delay of the NoteOn, and negative track delay so that you will hear them "sound" more on the grid. My kirk hunter libs are the same way, by the way. He told me that in order to capture all of the realism of the full string attack, the simple truth is that a string player starts playing the string slightly ahead of the beat and all that attack tone is there building up to a transient. Normally its the transient itself that needs to be on the beat to not sound late. So anyway, this is a common problem with string libraries in particular, not just CSS. But its particularly bad with that one or maybe more noticeable because of so many different articulations or something. But according to Kirk, that is the only way to get the full realism and sonic pleasure of the rosin on the string..its going to sound late from the moment the midi event starts to make the sound. Therefore, you can either trigger the midi slightly early, like a real player does intutively, or some kind of script like this.

 

Anyway, back to noteOff. With NoteOff, it doesn't really need to be corrected. You want it to end exactly at the time you see it ending on your pianoroll. Therefore if you are going to use 300ms negative track delay, you need to make sure all NoteOff's are delayed exactly 300ms. They don't need to, and should not; match the delay of their corresponding NoteOn.

 

 

I have tried implementing what you have suggested for legato transitions, and the delay is working as it should, however it is only letting NoteOns through to the instrument, so articulations are not switched. NoteOffs and modulation data is also lost. Here is the code.

 

You just need to account for those types... I updated your code a bit to show kind of what I mean. (see below). Also note that previously the code was not passing the CC58 through either. And even more complicated then that, the CC58 needs to be delayed and sent right before the Note that will be delayed. See if you can understand how that is working, the code is starting to get a bit complicated now.

 

Also note that all other midi events are being sent with exactly 300ms of delay...just like Note Offs

 

/* Editable Delay Times */
LegatoStartSlow = 0;
LegatoStartMedium = 500;
LegatoStartFast = 1000;
LegatoSlow = 1500;
LegatoMedium = 2000;
LegatoFast = 2500;
Spiccato = 250;
Staccatissimo = 245;
Staccato = 240;
Sfz = 240;
Pizzicato = 250;
BartokSnap = 250;
ColLegno = 250;
Trills = 250;
Harmonics = 200;
Tremolo = 200;
MeasuredTremolo = 200;
Marcato = 250;
MarcatoOverlay = 250;

/* Keyswitch CC */
var ccnum = 58;
var lastCC = 0;
var delay = 0;

var cc = new ControlChange;
cc.number = ccnum;

function HandleMIDI(event) {

   if(event instanceof ControlChange && event.number == ccnum) {
       lastCC = event.value;
       return;
   }
   
   if(event instanceof NoteOn) {
       if(lastCC >=6 && lastCC <=8) {
           if(event.velocity >=1 && event.velocity <=64) {
               delay = LegatoStartSlow;
           }
           else if(event.velocity >=65 && event.velocity <=100) {
               delay = LegatoStartMedium;
           }
           else if(event.velocity >=101 && event.velocity <=127) {
               delay = LegatoStartFast;
           }
       }
       else if(lastCC >= 9 && lastCC <= 10) {
           if(event.velocity >=1 && event.velocity <=64) {
               delay = LegatoSlow;
           }
           else if(event.velocity >=65 && event.velocity <=100) {
               delay = LegatoMedium;
           }
           else if(event.velocity >=101 && event.velocity <=127) {
               delay = LegatoFast;
           }
       }
       /*
          .
          .
          .  More conditions here
          .
          .
       */
       event.trace();
       
       cc.channel = event.channel;
       cc.value = lastCC;
       cc.sendAfterMilliseconds(delay);
       
       event.sendAfterMilliseconds(delay);
   }
   
   // all other events including NoteOff, just pass through 300ms late
   else {
       event.sendAfterMilliseconds(300);
   }
}

 

lots to digest here... let me know if you have any questions.

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...