Jump to content

Scripter- Humanize Notation Program Quantized Note Length


Recommended Posts

Can someone create a simple and clear script for Logic’s Scripter that does the following if even possible?

 

The script will assume that MIDI notes have been imported from a notation program or all note lengths has been quantized so all note values have perfectly quantized lengths (like MIDI looks exported from Finale.)

 

It will rely on a Logic Articulation Set that has at a minimum the following articulations:

 

No. Articulation

1 Sustain

2 Legato

3 Marcato

4 Staccato

5 Staccatissimo

6 Tenuto

 

 

-If the articulation is marked Legato it will sound a 5% longer MIDI note or 105% of the original length MIDI note to the instrument.

 

-If the articulation is marked Marcato it will sound a 15% shorter MIDI note or 85% of the original length MIDI note to the instrument.

 

-If the articulation is marked Staccato it will sound a 50% shorter MIDI note or 50% of the original length MIDI note to the instrument.

 

-If the articulation is marked Staccatissimo it will sound a 75% shorter MIDI note or 25% of the original length MIDI note to the instrument.

 

-If the articulation is marked Tenuto it will sound a 5% shorter MIDI note or 95% of the original length MIDI note to the instrument.

 

-All other notes of any other articulation or without articulations will sound a 15% shorter MIDI note or 85% of the original length MIDI note.

Link to comment
Share on other sites

Can someone create a simple and clear script for Logic’s Scripter that does the following if even possible?

 

The script will assume that MIDI notes have been imported from a notation program or all note lengths has been quantized so all note values have perfectly quantized lengths (like MIDI looks exported from Finale.)

 

It will rely on a Logic Articulation Set that has at a minimum the following articulations:

 

No. Articulation

1 Sustain

2 Legato

3 Marcato

4 Staccato

5 Staccatissimo

6 Tenuto

 

 

-If the articulation is marked Legato it will sound a 5% longer MIDI note or 105% of the original length MIDI note to the instrument.

 

-If the articulation is marked Marcato it will sound a 15% shorter MIDI note or 85% of the original length MIDI note to the instrument.

 

-If the articulation is marked Staccato it will sound a 50% shorter MIDI note or 50% of the original length MIDI note to the instrument.

 

-If the articulation is marked Staccatissimo it will sound a 75% shorter MIDI note or 25% of the original length MIDI note to the instrument.

 

-If the articulation is marked Tenuto it will sound a 5% shorter MIDI note or 95% of the original length MIDI note to the instrument.

 

-All other notes of any other articulation or without articulations will sound a 15% shorter MIDI note or 85% of the original length MIDI note.

Scripter.png.1758d483cf5a1db15d32af7557f5a59f.png

In Scripter you get events as they happen. For your request on changing the note length depending on a articulation that was set before hand, this isn't possible in Scripter for shorten the length.

Notice that you get NoteOn-NoteOff pairs. When you subtract the NoteOff-NoteOn positions, you get the length but the only problem is the note has already played at least the length of the NoteOff until you send the NoteOff then it stops. the only thing you can do is make the note longer, not shorter.

 

CoreMidi.png.5f38d6db53b47028ea8c008645dab039.png

If you look at CoreMidi, you get two events and the starting position and the duration of the note is in a single event. Once you receive a CoreMidi event you'll have the length then you can readjust the duration to the desired length based the articulation you've set before hand, either shorter or longer.

Using CoreMidi requires a Objective-C or Swift application to be written.

Link to comment
Share on other sites

Presuming you have articulation id’s To specify how to handle for each note...

 

Regarding shortening notes in scripter that could only be possible using lookahead processing which is trickier to say the least, but yes could be possible. It would necessarily add a large amount of latency which you would then have to manually compensate for by using negative track delay.

Link to comment
Share on other sites

Presuming you have articulation id’s To specify how to handle for each note...

 

Regarding shortening notes in scripter that could only be possible using lookahead processing which is trickier to say the least, but yes could be possible. It would necessarily add a large amount of latency which you would then have to manually compensate for by using negative track delay.

moss.gif.9c684f74f10ace64caaffc2009adcdf4.gif

Link to comment
Share on other sites

Here is a very short and very simple example of using Lookahead to shorten midi notes to 50% of their original length:

 

var NeedsTimingInfo = true;

var LOOKAHEAD = 500;   // ms

var noteOns = [];

function HandleMIDI(event) {

   // NoteOff
   if( event instanceof NoteOff) {
   
       if(noteOns[event.pitch] == undefined) {
           // error, where was the NoteOn?
           event.sendAfterMilliseconds(LOOKAHEAD);
           return;
       }
       
       let duration = msFromBeats(event.beatPos - noteOns[event.pitch]);
       noteOns[event.pitch] = undefined;
       
       let shorten = duration * 0.50; 
       let delay = LOOKAHEAD - shorten;
       
       if(delay < 0) {
           event.send();
       }
       else {   
           event.sendAfterMilliseconds(delay);
       }
   }
   
   // NoteOn
   else if (event instanceof NoteOn) {
       noteOns[event.pitch] = event.beatPos;
       event.sendAfterMilliseconds(LOOKAHEAD);   
   }
   
   // All other event types
   else {       
       event.sendAfterMilliseconds(LOOKAHEAD);   
   }
}

function msFromBeats(beats) {
   let info = GetTimingInfo();
   return Math.round( 60000 * (beats/info.tempo));
};

 

I intentionally kept this script as simple as possible in order to demonstrate the concept. In order to test it, set the track to -500ms negative track delay. On playback you'll hear the note durations cut in half.

 

Here are some challenges, some easier then others, which would probably need to be added to a robust script for this purpose:

 

  1. If you hit STOP exactly in between the time when the NoteOff has come in, but has not actually been played yet with the lookahead delay, then it will never get played, and there might be hanging notes. There are ways this could be handled in Scripter that I don't want to get into right now, but if you get any hanging notes..that's why.
     
     
  2. the noteOns[] array in the above example really should be a two dimensional array that tracks each midi channel separately, but if you're only using the script for one channel at a time, then it doesn't matter.
     
     
  3. if you have any notes that need to be shortened by more than 500ms, then there is not enough lookahead available to handle that situation because LogicPro track delay can only be set up to -500ms. You can alternatively use Expert Sleepers Latency Fixer, which will provide room to shorten notes by up to a second and then LatencyFixer will handle the negative track delay compensation by faking out the PDC system, it can handle up to 1sec. But really 500ms of "shortening" should be more than enough. If and when you have a note that has to be shortened by more than the lookahead amount, the above script will simply shorten it by the lookahead amount. But might run into problems shortening staccatisimo by a factor of 75% on on longer notes...
     
     
  4. This script may or may not have problems when you have overlapping notes... (ie, two note Ons of a given pitch before either of their matching NoteOff's come through). I didn't test for that, but something to watch out for that might require more complicated scripting to handle it right.

Edited by Dewdman42
Link to comment
Share on other sites

Here's a more complete version that handles different factors per articulationID, handles lengthening the legatos too. Better check for NoteOff.

 

var NeedsTimingInfo = true;

var LOOKAHEAD = 500;   // ms

// articulationID based duration adjustments
var factors = [0, 1.05, 0.85, 0.50, 0.25, 0.95];

var noteOns = [];

function HandleMIDI(event) {

   // NoteOff
   if( isNoteOff(event) ) {
   
       if(noteOns[event.pitch] == undefined) {
           // error, where was the NoteOn?
           event.sendAfterMilliseconds(LOOKAHEAD);
           return;
       }
       
       let duration = msFromBeats(event.beatPos - noteOns[event.pitch]);
       noteOns[event.pitch] = undefined;
       
       let factor = 0.85;  //default 
       if(event.articulationID != undefined && event.articulationID > 0
               && factors[event.articulationID] != undefined) {
           factor = factors[event.articulationID];
       }
       
       let shorten = duration * (1-factor); 

       let delay = LOOKAHEAD - shorten;
       
       if(delay < 0) {
           event.send();
       }
       else {   
           event.sendAfterMilliseconds(delay);
       }
   }
   
   // NoteOn
   else if (event instanceof NoteOn) {
       noteOns[event.pitch] = event.beatPos;
       event.sendAfterMilliseconds(LOOKAHEAD);   
   }
   
   // All other event types
   else {       
       event.sendAfterMilliseconds(LOOKAHEAD);   
   }
}

function msFromBeats(beats) {
   let info = GetTimingInfo();
   return Math.round( 60000 * (beats/info.tempo));
};

function isNoteOff(event) {
   if(event instanceof NoteOff) {
       return true;
   }
   else if(event instanceof NoteOn && event.velocity < 1) {
       return true;
   }
   return false;
}

 

Note that for the staccatisimo articulation that is shortening the length by 75% will have problems when applied to notes of longer duration since the lookahead of 500ms may not be sufficient.

Link to comment
Share on other sites

  • 2 weeks later...
[soundCloud][/soundCloud]Hey- sorry I didn't see your reply. I just tested this a various speeds with a -500ms offset and it seemed to work well EXCEPT and ironically, there doesn't seem to be an audible difference between the staccato and the staccatisimo lengths at least when listening. I think what is happening is like you said, the staccatisimo articulation can only be applied to an already short note. I assume it would need to be assigned to a note shorter than 500ms. I may try to alter this script by adding other articulations/lengths, but I'm not sure I quite understand... It looks like you set up an array of lengths, and then told the script to check for sequentially what articulation ID/number was chosen starting with "greater than zero?" I guess if I add any new articulations, they will need to be sequentially starting at ID 7 after tenuto, and then I will need to add the new lengths to the end of the array. Am I thinking correctly? Also after running some more tests, it's like the staccato and staccatissimo articulations don't work back to back. I could keep shortening the staccato time and hear it get a short as 25, I think. I'm not sure really but thought I'd share!
Link to comment
Share on other sites

Yes you can add more articulation ids as needed

 

You could also try increasing the lookahead to more then 500ms but then you’ll need another solution for negative track delay since logicpro can only do 500ms in the track delay setting. You can use expert sleepers latency fixer to get as much as 1000ms of negative track delay and you might be able to stack those to get more. But why do you need to apply staccato to long note durations?

 

Please describe exactly the scenario why back to back it stopped working.

Link to comment
Share on other sites

http://michaelrasbury.org/HumanizeFinale.zip

 

I have dropped a zipped folder on my server that includes a Logic Project, the script, and the articulation set if you just want to open it on your end. I will also try to explain the test. I loaded sampler and used its test tone so that there is no decay at the end of the tone. I set up a four measure MIDI region. The BPM was initially at 120, but I found even speeding things up to 220 yielded the same results, although faster of course. There is a -500.0ms track delay in the drop down menu.

  • The first measure has eight exact eighth notes. The first two have the staccato articulation chosen, the second two have the staccatissimo articulation, the next two go back to staccato and the final two have the staccatissimo articulation. The staccatissimo ones don't work as you thought they might not.
    The second measure is four exact quarter notes with the first two using the marcato articulation and the second two using the tenuto articulation. These seem to work as expected.
    The third measure contains four exact quarter notes alternating between adjacent pitches and use the legato articulation. These don't seem to be longer than 100 percent as I would expect to hear the two pitches overlap a little when triggering. I went back to the script and changed the length in the array from 1.05 to 1.20 and observed the notes seem to never be able to last past 1 or full length.
    The fourth measure uses two exact half notes and has the sustain articulation chosen. These sound unaltered as expected.

Link to comment
Share on other sites

found a typo in the script earlier. In the array of durations, you need an entry for 100% sustains. My mistake in what I posted. So change that line to include a "1" for 100% on sustains, at the second position in the array like this:

 

// articulationID based duration adjustments
var factors = [0, 1, 1.05, 0.85, 0.50, 0.25, 0.95];

 

The first position in the array is array index 0 and articulationID=0 means no articulation ID. You could alternatively design your articulation set in such a way that articulationID=0 means use 100%, which is not a terrible idea, so that the default is full sustain.

 

// articulationID based duration adjustments
var factors = [1, 1, 1.05, 0.85, 0.50, 0.25, 0.95];

 

In this example, no articulationID is the same as "sustain", both being 100%

 

hope that makes sense.

 

Try that again, probably things were out of wack because of not having a complete array before...

Link to comment
Share on other sites

If you need more than 500ms of lookahead, then look into using the following plugin, INSTEAD OF using the track negative delay setting:

 

https://www.expert-sleepers.co.uk/downloads/latencyfixer_1_0_3.tgz

 

latency fixer will let you report up to 1000ms of latency to LogicPro and then LogicPro will automatically use p plugin delay compensation. You have to change the line in the script that specifies the lookahead amount also to 1000.

 

var LOOKAHEAD = 500;   // ms

 

It might even be possible, but I'm not sure, to stack up multiple instances of that LatencyFixer plugin to get even more lookahead delay if you want.

 

That would essentially make it possible to apply staccatisimo, as a percentage, to longer held notes and still work properly. That is unlikely scenario of happening though honestly. The thing is that whatever the resulting duration will be, after applying the %, the amount that is cut out cannot exceed 500ms (or 1000ms if you use the plugin). Realistically you are talking mostly about quarter notes or less from Finale I would think. But a quarter note is 500ms at 120BPM. So that would still work, but if the tempo is....wait for it...I guess 25% slower. (maybe) .then the amount cut out would exceed 500ms.

 

another thing you might consider is doing it differently instead of an actual percentage. because I would contend that a staccato eighth note should sound about the same as a staccato quarter note, if you know what I mean. Staccato is staccato, not really a percentage of the value coming from finale. So you might want to redo your script to have it specify that actual duration, in fractions of a beat, for each articulation type. Same issue though, the amount cut out of the duration cannot exceed the lookahead value, whatever it is.

Link to comment
Share on other sites

and the more I think about it, fractions of the beat might also not be the right way to specify articulation durations...because at faster or slower tempos....I think staccato probably still sounds about the same with most instruments. Other articulations may vary depending on tempo too though...so perhaps it could get a little complicated if you really want to do it right...but I'll leave that as an experiment for you to think about and we can revisit some of the math later if you decide you want to try.
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...