# How to reliably detect note-off?



## kotori (Jan 17, 2007)

This should be really simple, but somehow I cannot think of the right way to do this at the moment. I want to detect note-off. If the script is loaded in a script slot with an empty script slot to the left it will receive two note-offs for notes sustained using the sustain pedal - one when the pedal is lifted and one when the note is released. Now one can always ignore the first release callback by checking whether the pedal is pressed. That far everything is fine. However if CC64 is set to act as "CC Only" in the instrument settings the note will end on it's first and only release callback and this will look exactly the same as in the case of the first callback for the previous case. So how does one tell these apart?

Btw. I have an update to the crossfade script with support for release samples. Dealing reliably with the "CC Only" case is the only missing thing.


----------



## FirmamentFX (Jan 17, 2007)

Is there no way of KSP detecting instrument settings? (in much the same way that you can get javascript to detect browser settings)


----------



## kotori (Jan 17, 2007)

FirmamentFX @ Wed Jan 17 said:


> Is there no way of KSP detecting instrument settings? (in much the same way that you can get javascript to detect browser settings)


No, unfortunately not. There are some functions to detect what groups you have selected, and it's possible to set almost all parameters which can be modulated/automated, but there's no access to the settings.

The problem with KSP is that NI don't seem to have anticipated this kind of general scripts which should work for a wide range of instruments. To me it seems like they more had sample developers writing customized scripts for a certain library in mind.


----------



## gh (Jan 17, 2007)

Hi Nils!

What about using the EVENT_ID? This should be unique.

Günter


----------



## kotori (Jan 17, 2007)

gh @ Wed Jan 17 said:


> What about using the EVENT_ID? This should be unique.


Hi Günter,
In the case of the sustained note which will trigger two release callbacks (one when the note is released and one when the pedal is lifted) I will get the same EVENT_ID in 'on release' both times since it's the same note. Thanks for the suggestion though.

Nils


----------



## gh (Jan 17, 2007)

> will get the same EVENT_ID in 'on release' both times since it's the same note



Hi Nils!

That is exactly my point. 

Store all EVENT_ID's + the time information when the event occured in an array.
Store the pedal event + time information in another array.

In the release it should now be possible to define whether it is the first or second release call back (maybe in connection with %KEY_DOWN) and when to take action.

I have never looked into a "CC only" scenario for CC64 but I think it should be possible.

Günter


----------



## kotori (Jan 17, 2007)

Hi Günter,
I still don't see how one at the time of the first release callback (which might be the last in case "CC only" is active) can determine whether or not there will be another callback in the future. Btw. %KEY_DOWN[$EVENT_ID] is always 0 in the release callback AFAIK, so it doesn't provide any help.

Cheers,
Nils


----------



## Big Bob (Jan 17, 2007)

Hi Nils,

When the Instrument options are set for anything but CC only (ie the sustain pedal is active), as long as the pedal is down, note_off calls continue to trigger RCBs (at least in slots N+2 and up). Since this is the case, perhaps you could include some code in the RCB to issue a 'tagged' note_off and then wait a short period of time to see if another RCB is triggered with that event tag. If so, you reset the tag and exit. If not, you could conclude that there will be no more RCBs triggered and the note has ended. Maybe something like this:


```
if EVENT_PAR[3] = 1234
    PedalStillDown := 1
    exit
  else
    set_event_par(EVENT_ID,3,1234)
    note_off(EVENT_ID)
    PedalStillDown := 0
    wait(100)
    if PedalStillDown = 1
      set_event_par(EVENT_ID,3,0)
      exit
    else
      NoteOffFound
    end if
  end if
```

I haven't actually tried this so it may need some refinement, but, maybe you can use this as the germ of an idea?

God Bless,

Bob


----------



## Big Bob (Jan 17, 2007)

Phooey!

I just had a chance to try this and it doesn't seem to work :cry: . Apparently, issuing a note_off call from the RCB doesn't want to produce another RCB trigger (perhaps to prevent and endless loop situation?). I may have missed this in my NCB/RCB report. :oops: 

During my testing I was generating note_off calls from a ui_control block in each of the script slots. While it didn't matter which slot issued the note_off call, it may matter what kind of callback they originate in. If this is the case, then maybe the suggested scheme could still be made to work if we find a way to remotely produce a note_off from the RCB.

When I get a little more time I'll see if I can come up with something.

Bob


----------



## kotori (Jan 17, 2007)

Hi Bob,



> Apparently, issuing a note_off call from the RCB doesn't want to produce another RCB trigger


After an ignore_event($EVENT_ID) and a wait(1) it will as long as the note was not generated within the script or in the script slot just to the left. So in fact it's possible to make Kontakt go into a loop. It seems there's some kind of protection because after about 700 000 loops (different each time it seems) it stops. I'm not sure I completely understand the logic of your script. It seems it tries to detect CC64 transients but I'm not sure how this could be used to tell the two cases of the first RCB invokation apart.

Cheers,
Nils


----------



## kotori (Jan 17, 2007)

Wow! Thanks a lot Bob. I'll try to digest this tomorrow. It's a bit late here now so I just skimmed through it. If I understood it correctly you basically perform a kind of test note-off to see whether it triggers the RCB or not. Clever!

Cheers and good night,
Nils


----------



## Big Bob (Jan 17, 2007)

kotori @ Wed Jan 17 said:


> Wow! Thanks a lot Bob. I'll try to digest this tomorrow. It's a bit late here now so I just skimmed through it. If I understood it correctly you basically perform a kind of test note-off to see whether it triggers the RCB or not. Clever!
> 
> Cheers and good night,
> Nils



Hi Nils,

You got it exactly right, you see if you can produce another RCB trigger or not. If you can, the sustain pedal is still active and vice versa.

Glad you are finally going to bed, it must be kind of late there, no? 

But, for your morning coffee, I'll just post this revised version (which might be a little easier to follow). I redid the code with polyvars instead of the EPs and removed some of the diagnostic test code. BTW I did some polyphonic testing and both this and the prior version seem to work OK, at least superficially. 

Sleep well and God Bless you my Friend,

Bob

*on init*
``*declare* *const* Test := 1234
``*declare* polyphonic PedalDown
``*declare* polyphonic Mode
``*declare* ui_label Display (2,6)
``set_text(Display,'')
``message('')
*end on*

*on release*
``*if* Mode = Test```_{ This only occurs if pedal is still active }_
````PedalDown := 1 _{ Indicate that Pedal is Still Down }_
``*else*``_{ Normal, non-test mode }_
````wait(100)```````````_{ Gimmick to allow a note_off to trigger RCB }_
````PedalDown := 0``````_{ Assume Pedal Up }_
````Mode := Test````````_{ Now test that assumption }_
````note_off(EVENT_ID)``_{ Try for another RCB trigger }_
````wait(100)```````````_{ wait for feedback }_
````*if* PedalDown = 1````_{ Feedback received, Pedal Still Down }_
``````Mode := 0`````````_{ Resume normal, pre-test mode }_
``````add_text_line(Display,'Note ' & EVENT_NOTE & ' still sustained')
````*else*``_{ No feedback, ie Re-trigger failed, must be end of event }_
``````add_text_line(Display,'Note ' & EVENT_NOTE & ' ended')
````*end if*
``*end if*
*end on*

BTW I didn't conduct any experiments to see how short the two waits can be, 100 usec is just the first thing I tried.


----------



## kotori (Jan 18, 2007)

Thanks a lot Bob, it seems to work really well!  
I changed the wait time to 1 microsecond and that too seems to work just fine, although it's hard to know for sure.
I wonder what the total delay is for figuring out which release case it is. I suspect that two wait(1) really add up to more than 2 microseconds. I want to play release trigger groups at the right time, so all extra delay could be a problem. But maybe it's too small to be noticable.

Thanks again!

Cheers,
Nils


----------



## Big Bob (Jan 18, 2007)

kotori @ Thu Jan 18 said:


> Thanks a lot Bob, it seems to work really well!
> I changed the wait time to 1 microsecond and that too seems to work just fine, although it's hard to know for sure.
> I wonder what the total delay is for figuring out which release case it is. I suspect that two wait(1) really add up to more than 2 microseconds. I want to play release trigger groups at the right time, so all extra delay could be a problem. But maybe it's too small to be noticable.
> 
> ...



Glad to hear that it seems to work OK and I'm also glad to hear that it still works with very short delays. I agree that it's doubtful that a 1us wait will actually turn out to be that short (unless maybe there is actually nothing else for the KSP to do while it waits). As far as audibility of delays, I think waits of less than a fraction of a ms should be fairly unnoticeable. Also, I think the 'wait' right after the else clause starts can safely be made 1us since this wait is more or less in the nature of a gimmick to allow a note_off() call to be honored (maybe I should add something about this to the NCB/RCB report). The second 'wait' may or may not need more time to guarantee that the note_off() does its job and re-triggers the RCB.

But isn't the N, N+1, RCB thing somewhat of a problem? If you are planning to use this technique for your Crossfade script, doesn't it ignore the original note (from slot 0) and then generate a set of notes from each velocity layer? If so, won't this 'end of note test' have to be performed two slots higher in the chain?

Regarding the slot N and N+1 RCB problem, I'm beginning to think that the way N+2 and above work would be preferable to the way N and N+1 work don't you? Maybe you could start urging NI to make all the slots behave uniformly but as the higher ones do (not as N and N+1 do)?

Have a great day Nils,

God Bless,

Bob


----------



## kotori (Jan 18, 2007)

Big Bob @ Thu Jan 18 said:


> But isn't the N, N+1, RCB thing somewhat of a problem? If you are planning to use this technique for your Crossfade script, doesn't it ignore the original note (from slot 0) and then generate a set of notes from each velocity layer? If so, won't this 'end of note test' have to be performed two slots higher in the chain?


Yes, it's probably still not applicable to my script. But it's still interesting to know. 



> Regarding the slot N and N+1 RCB problem, I'm beginning to think that the way N+2 and above work would be preferable to the way N and N+1 work don't you? Maybe you could start urging NI to make all the slots behave uniformly but as the higher ones do (not as N and N+1 do)?


I'll do that. 

Btw. Bob, what do you think would be the best way to make the crossfade script work with SIPS? (I've dropped all polyphonic stuff in the latest script - it stores all layers of all notes in arrays instead)

Cheers,
Nils


----------



## Big Bob (Jan 18, 2007)

Hi Nils,



> Btw. Bob, what do you think would be the best way to make the crossfade script work with SIPS? (I've dropped all polyphonic stuff in the latest script - it stores all layers of all notes in arrays instead)



You must have read my mind :wink: . I was just thinking about that this morning and your question is indeed a good question! I have a few ideas about this but they're not fully thought out yet. While we may be able to collaborate on some form of integration, I wonder if we shouldn't do it in such a way that it will make at least a start toward solving the more general problem of cascaded scripts?

I've been thinking about this a lot lately and as formidable as a general solution might be, I think there are some very useful things that we can specify that we'd like to see all new scripts contain. Perhaps we now have sufficient motivation to begin working on this problem by making SIPS and XFade the first pair of scripts to meet these cascadable specs? Of course it will probably be faster to solve this one specific problem without regard of the general problem but that may not be the best in the long run.

Why don't you let me chew on this for a few days and I'll get back to you. In the meantime, why don't you think about how you would feel about collaborating with me on solving this specific problem while working toward some more general solution for the future? Might be a lot of fun if I can hold up my end :???: 

God Bless,

Bob


----------



## Big Bob (Jan 18, 2007)

Hi Nils,

One way of allowing SIPS & XFade to work in concert, that I think may work, would be something like this. With the SLS ahead of XFade, when the SLS receives a new note it requests velocity/layer data from XFade. Then, instead of generating just one note, the SLS generates a complete velocity *set*. When the SLS crossfades and bends the first and second received notes it now crossfades and bends the first and second *set *of notes. The XFade script then operates on the *'sets'* of notes choosing two from each *set* and blending them per the mod wheel function. We could then put the SVS after the XFade script and add your release trigger code there. Since no new notes would be generated after the SLS, the SVS would be 2 slots higher and thus could properly detect the end of note situation. I think we could also make sure that the SLS will function in Slot 1 if need be.

This general scheme would require bi-directional interscript communication, but, I think we can include that (along with a half-dozen or so other ideas I'll discuss with you) in some 'standardized' modules. These in turn ultimately might lead to a more general solution of the cascaded scripts problem. I've run a few quick tests to make sure that the fade functions and the change_vol functions can be used simultaneously and it looks favorable.

I won't flesh this out any further until you have a chance to ponder the general idea and/or propose some alternate ideas. So, let me know what you think.

God Bless,

Bob


----------



## kotori (Jan 19, 2007)

Hi Bob,

It seems we're thinking about roughly the same solution, namely more or less integrate the functionality of the crossfade script into SLS (or some special version of it). If I translate the xfade script into something more module-oriented this might work. Maybe the release trigger code could would be better implemented in SLS itself (since we mute the incoming note instead of ignoring it I guess it should work as long as the script is loaded with a free slot to the left).

Another solution might be to come up with an interface so that all change_vol, fade_in, fade_out and their parameters could be sent to the xfade script so that it could reproduce the effect for all layers there. This would make the scripts more decoupled which is a good thing, but it might be tricky to implement a reliable solution. I'll think more about both solutions. In the meantime I posted a feature request on the NI forum which if implemented would make it possible to make the two scripts work together in a matter of minutes. It would also fix many of the release trigger problems I think. I hope it'll get some support although the post being so long.

Cheers,
Nils


----------



## Big Bob (Jan 19, 2007)

Hi Nils,



> It seems we're thinking about roughly the same solution, namely more or less integrate the functionality of the crossfade script into SLS (or some special version of it).



Actually, the way I envisioned it, your XFade script could remain pretty much intact running in its own slot. The SLS could also remain pretty much as is with the exception of handling two 'sets' of notes rather than just two notes. The rest of the scheme would rely on a standardized interscript communication protocol to be hammered out.


> Maybe the release trigger code could would be better implemented in SLS itself (since we mute the incoming note instead of ignoring it I guess it should work as long as the script is loaded with a free slot to the left).



Maybe I don't fully have the correct picture here. Do you only need to detect the end of the original MIDI stream note rather than the end of the generated set? I was thinking the latter, in which case the release code will have to be 2 slots beyond the slot where the note set is generated.

BTW I was just at the NI forum and I must have missed your post there so I'll head back over there after I finish this post.

God Bless,

Bob


----------



## Big Bob (Jan 19, 2007)

Hi again Nils,

I just read your post on the NI forum and I think it would be wonderful if NI will someday do it. However, in the meantime, my idea was to accomplish much the same thing by mutual cooperation between scripters and a series of standard protocols. Even if NI does implement your suggestions within my lifetime, forming something like a Script Writers Association and establishing some standards for interscript communication and cooperation might yield benefits that would transcend the NI improvements.

I think I'll start another thread with some 'food for thought' along these lines. Watch for it at your local newstand :wink: 

Have a Great Day Nils,

God Bless,

Bob


----------



## Big Bob (Jan 19, 2007)

Hi Nils,

I think if we do it right, making the SLS and XFade scripts work together will in no way prevent future embellishments of either script. The interscript communication protocol I have in mind will easily accomodate dynamic sizing, etc. Even those changes to the XFade script which may not be anticipated would at most require a minor modification of the SLS script to accomodate it (and vice versa). The secret is all in the generality of the CSS (see my latest post on Roses Have Thorns).

Part of the problem here is that I haven't disclosed a lot a details simply because I don't want to do a lot of work only to discover no one cares about the idea. I think once all these ideas are put forth and kicked around, something quite interesting may come out of it. Time will tell.

God Bless you my Friend,

Bob


----------

