View Full Version : Timing Problems with the KSP

Big Bob
07-04-2005, 04:03 PM
The KSP has a timing problem with the play_note function, causing it to handle very short or zero-length notes improperly.

The play_note function takes 4 parameters and is of the form:

play_note(p1,p2,p3,p4) (See page 12 of the Kontakt Script Language Manual, KSLM)

This function is usually used to generate additional notes when a MIDI note-on message is received and as such this function is usually placed in the ‘on note’ callback block. The p4 parameter specifies how long the generated note should be held. For p4 > 0, the note is held for p4 microseconds. In addition, there are two special values of p4. When p4 = 0, the generated note plays the corresponding sample from beginning to end or, in the case of a looped sample, plays forever until stopped by something. When p4 = -1, the duration of the generated note is slaved to the ‘parent’ note that produced the ‘on note’ callback. When the ‘parent’ note ends, the generated (or ‘child’) note(s) also end. This causes ‘on release’ callbacks not only for the parent note but also for each generated ‘child’ note slaved to it.

If we write a simple ‘octave-doubling’ script, it would be as follows:

on note

play_note($EVENT_NOTE - 12,$EVENT_VELOCITY,0,-1)

end on

Every time you play a note on your keyboard (or send one to K2 from your sequencer), it will be doubled with a note one octave down. When you release the key (or the sequencer note ends), the generated octave will also end. When you play a note, the ‘on_note’ callback is executed and thus the play_note function is also executed. When you release the key that caused the ‘on note’ callback, the ‘on release’ callback block will be executed twice (assuming an ‘on release’ block exists). The first call is because the ‘parent’ note has ended, and the second call is because the ‘child’ note (the lower octave) has also ended (by virtue of the p4 = -1).

Now, we come to the problem. As long as the parent note is around 4ms or more in duration, the octave is generated and both notes sound (with a short ‘blip’) and ‘on release’ callbacks for both parent and child notes are executed one after the other. This is as it should be. However, when the duration of the parent note is less than 3 ms or so (about 2 or 3 ticks at 480 ppqn at a tempo of 120 BPM), the parent note ‘blips’ but the child note most often will hang on, in spite of the fact that both release callbacks are made. The shorter the parent note, the more likely it seems to be that the child note will hang but it is a somewhat probabilistic situation. Even with a zero-length parent note, the child note sometimes shuts off with the parent, but it’s fairly rare. Apparently there is some kind of ‘race’ condition, perhaps with an asynchronous internal timer (or something similar to this), contributing to the somewhat random behavior of this problem.

You can easily demonstrate this problem yourself by creating a short MIDI sequence consisting of 6 or 8 notes in a row, each separated by about 1 bar. Make these notes as short as your sequencer allows, zero if possible. If you make each note a different pitch you will be able to more easily hear each of the stuck notes. Now, load an instrument with a long sustain, I usually use the 1960s E-Organ from the K2 library. Type in the simple 3-line script above and then play the sequence. If the KSP miraculously does the right thing for all 8 notes, all you should hear are 8 short ‘blips’. But if the KSP behaves as it always does for me (and several others who have tried this), typically 5 or more of the 8 notes will hang. I should mention that this problem occurs in plugin or standalone modes with only minor differences. If you want to try this test (but you’d like to avoid having to create the sequence), I made a short, Standard MIDI test file with a series of 8 blip notes followed by a final, 1-beat chord. I’ll attach this file on the forums that allow attachments but if the forum you’re reading this on doesn’t, you will find this file attached to my posting on NI’s forum (in the thread with the same name as this one).

Since such short notes don’t occur often, this problem can go unnoticed easily. Playing a keyboard glissando or lightly brushing a neighboring key (of the one you intended to hit), are just two examples of how such ‘ghost’ notes can be produced. I first ran into this hanging note problem when I was testing and debugging a harmonizer script. For this I was using K2 in standalone mode and driving it with my keyboard. Since it was a new script, I naturally suspected the cause was a bug or two in my code. But, after a lot of hair pulling (and I don’t have much to pull), I was able to reduce my program to a single line of code and it still occasionally produced stuck notes. With much more hair pulling and time, I was finally able to more or less reduce the problem to its essence, which is the subject of this posting.

Hopefully NI will fix this problem soon but, in the meantime you may be interested in a ‘work around’. Obviously, one way to work around it is to never feed the KSP with short notes. If you always drive K2 from a sequencer, then all you need do is to hunt down and ‘edit out’ ghost notes. But, for those situations where we’re driving K2 from a ‘live’ keyboard, it would be nice if there was something we could add to our scripts to mitigate this problem. I have yet to find any ‘perfect’ work-around but the following method does help for many situations. So, if you’re experiencing a lot of hung notes generated by the KSP, you might try to put a note_off in the ‘on_release’ block and execute it when the parent note ends.

For example, for the simple octave-doubler discussed above, write your code something like this.

(Incidentally, the formatting for the following coding may not come through correctly, but hopefully you’ll still be able to read it OK)

on init

declare %Child_ID[128] { Array to hold child note Ids }

declare $I { Loop index, set to zero }

while ($I < 128)

%Child_ID[$I] := -1 { Fill ID array with impossible IDs }

end while

end on

on note { Save child’s ID at parent’s note index }

%Child_ID[$EVENT_NOTE] := …

play_note($EVENT_NOTE - 12,$EVENT_VELOCITY,0,-1)

end on

on release { When release is called by any parent, turn of the corresponding child’s note}


end on

While the above fix works well for short notes that are spaced (such as the ‘8-Blips and a chord’ test file), I have been able to create keyboard glissandos that contain a series of rapidly repeated short notes (usually of the same pitch). For that kind of situation, this fix will not work. In fact, it may make things worse. If multiple calls to ‘on note’ occur before any of the corresponding ‘on release’ calls, the ‘child’ ID array will be overwritten and some of the needed note_off ID’s will be lost..

If any of you can come up with a better fix for this problem, please post it.


One obvious way to kill a stuck note is to use the note_off function, but, finding a good way to use note_off isn’t as easy as you might think, owing partly to the fact that the note_off function doesn’t always do the logical thing. Moreover it doesn’t behave entirely as indicated in the KSLM. If anyone is interested in reading about what I have discovered (by painful trial and error) about the note_off function, email me and I’ll send you a copy.

Big Bob
07-04-2005, 08:29 PM
I forgot to mention that the fix will generally work with p4 = -1 or with p4 = 0. In some situations 0 works better than -1 and vice versa.

Big Bob
07-06-2005, 05:30 PM
Hey guys,

So far Tod (T.S.) is the only guy who has run this test and confirmed my conclusions. Before I report the problem to NI, it would sure be nice if more of you could either confirm or refute my conclusions.

Big Bob
07-08-2005, 07:20 PM
Hey fizbin,
If you happen to see this posting, try the following and tell me why the conditional compilation 'feature' doesn't seem to work properly for edit boxes.

on init
RESET_CONDITION(Debug) { Change RESET_ to SET_ to add debug stuff }
declare ui_knob $Blend(-50,20,1)
declare ui_table %Show_LH[12](2,2,5)
declare ui_table %Show_RH[12](2,2,5)
declare ui_value_edit $Bug_1(-1000,1000,1)
end on

07-09-2005, 01:41 PM
Looks like a bug to me. It is rendering the edit box when it should not be, but it is correctly ignoring the move_control for the edit box. Weird.

Too bad there's no easy way to report bugs to NI. Sometimes I wonder if they have anyone who cares monitoring their forums.


Big Bob
07-09-2005, 05:51 PM
Yeah, isn't that the truth! Looks like we're mostly on our own.