# Midi Latch/Hold Script



## Raptor4 (Feb 13, 2012)

Hi guys,
Is there any Midi Latch script which behaves as the Latch/Hold function of the hardware workstation synths.
For example, if you play one chord type (it is held), when you play another chord type the notes of the previous chord are OFF and the new chord is held etc.

I'm familiar with the Kontakt Factory ->Performance->Midi Latch preset but it does not behaves this way... In polyphonic mode the Latch function behaves as some kind of "Toggle Loop" - i.e you play a note or a few notes (they are held/sustained) and you have to play second time the same note(s) to terminate them. In "Mono" mode it is near to my wish but it is monophonic...

Are there any script or Kontakt instrument library on the market which offers such KSP, emulating the Latch/Hold function of the hardware synths?
Thanks !


----------



## marcmichaelmueller (Aug 28, 2012)

this is exaxtly what I'm searching for aswell. As a drummer in my band I'm just pushing some chords with one hand and want them to "latch" until i press a new chord or new single note (to get my hands free again as often as possible)

I'd need a latch script similiar like it works in the factory preset "Sequencing->Arpeggiator"

Since I'm very new to KSP at all the preset's code is a bit to heavy for me to get it worked out :(

Let me get this more clearly:
I need a latch that allows adding notes to it as long as one of the initial keys remain pressed. Once all keys have been released and a new key/chord is pressed start a new latch.

Anyone got an idea? 


regards

Marc


----------



## Big Bob (Aug 28, 2012)

Hi Marc/R4,

I'm not familiar with the hardware synth feature you are aiming for but, from Marc's description of what he wants, would something simple like this do the job?

*on init*
``message('')
``*declare* held_note_count
*end* on

*on note*
``inc(held_note_count)
``ignore_event(EVENT_ID)
``play_note(EVENT_NOTE,EVENT_VELOCITY,0,0)
*end* on

*on release*
``dec(held_note_count)
``*if* held_note_count = 0
````note_off(ALL_EVENTS)
``*end* *if*
*end* on


The above has to be compiled in Nils' editor of course or you will have to manually translate it by adding all the $ characters, etc.

Rejoice,

Bob


----------



## marcmichaelmueller (Aug 28, 2012)

wow, that's fast!

Thanks for your really quick answer 

Well I've compiled the script and copied into Kontakt, unfortunaly nothing is "latched" atm...just like normal behavior :(

regards

Marc

edit**
of course I had "applied" the script in Kontakt itself

looking more closer to the script I think i found at least one of the issues why it won't latch
if I release all notes it will send a "all notes off" as it is right now? What I meant was that the script should, after I release the keys, keep it latched until I engage a new note/chord

so what do i need to change?


----------



## Big Bob (Aug 28, 2012)

Hi Marc,



> if I release all notes it will send a "all notes off" as it is right now?



sorry, I thought that is what you wanted. However, it won't take much to change it to the way you have now described it. You just need to defer the note kill until after another note is played. I was just about to post a revised script when Rosie called me for lunch. :lol: 

So, right after lunch if you haven't worked it out yet, I'll post the needed changes.

Rejoice,

Bob

*EDIT: BTW, before I update the example, if I make it the way you are now saying you want it, how do you ever stop the last note? *:?


----------



## marcmichaelmueller (Aug 28, 2012)

manually by a controller (sustain pedal or button) since i need the chord/note to keep ringing while i keep hitting the drums 


....i hope i can add a "panic!" button that is assignable to a MIDI-CC by myself *lol*


----------



## Raptor4 (Aug 28, 2012)

Hey Bob, I hacked that a few months ago...
Do you remember my topic question about the array search flags where you gave me the key to that "True Midi Latch" ? 
OK, here it is below.
Rechoice :D 

marcmichaelmueller,
Copy and paste the code below. There are two UI controls only. 
1. "Latch" button:
- when it is ON then you enable the True Midi Latch function.
- when you switch it OFF you disable the function and it behaves as "Panic" (All Notes OFF)
- you can use and external CC to learn the Latch button etc.

2. "Clutch KS" box:
You can set it to any Note # and use that key as a Key Switch Clutch. When you roll the value edit box the key switch is colored in black. The KS note is ignored so it behaves a a pure "Clutch" switch. In other words the Global Latch function is working (if the Latch button is enabled) and you use Clutch KS to stop the held notes etc.
Note! When copy and paste the code for the very first time you have to roll the Clutch KS to assign the KS Note you want - it will be colored in black. After instrument saving everithing will be ok.

```
{***********************************************
True Midi Latch v1.0
Author: www.audiogrocery.com
Written by: Ivan Kovachev 
Modified: August 29, 2012
*************************************************}
on init
  make_perfview
  message("AUDIOGROCERY TM")
  set_script_title("True Latch")
  declare $n_num
  declare %note_reg[128]
  declare %note_id[128]
  declare $ks_Lt4_res
  declare ui_switch $Latch
  make_persistent($Latch)
  declare ui_value_edit $clutch_ks(0, 127, 0) 
  make_persistent($clutch_ks)
  _read_persistent_var($clutch_ks)
end on

on ui_control($Latch)
  if ($Latch=0)
    note_off($ALL_EVENTS)
  end if
end on

on ui_control($clutch_ks)
  $ks_Lt4_res := 0
  while ($ks_Lt4_res<127)
    set_key_color($ks_Lt4_res,$KEY_COLOR_NONE)
    inc($ks_Lt4_res)
  end while
  set_key_color($clutch_ks,$KEY_COLOR_BLACK)
end on

on note
  if ($Latch=1 and ($EVENT_NOTE # $clutch_ks))
    ignore_event($EVENT_ID)
    $n_num := search(%note_reg,1)
    while ($n_num # -1)
      note_off(%note_id[$n_num])
      %note_reg[$n_num] := 0
      $n_num := search(%note_reg,1)
    end while
    %note_id[$EVENT_NOTE] := play_note($EVENT_NOTE,$EVENT_VELOCITY,0,-1)
  end if
  if ($EVENT_NOTE=$clutch_ks)
    ignore_event($EVENT_ID)
    $n_num := search(%note_reg,1)
    while ($n_num # -1)
      note_off(%note_id[$n_num])
      %note_reg[$n_num] := 0
      $n_num := search(%note_reg,1)
    end while
  end if
end on

on release
  if ($Latch=1)
    ignore_event($EVENT_ID)
    %note_reg[$EVENT_NOTE] := 1
  end if
end on
```
Have fun o=< 
Regards,

Ivan


----------



## Big Bob (Aug 28, 2012)

Hey R4,

I'm a little perplexed :? ( but that's not too unusual) :lol: 

I thought you were the first poster asking how to do this and here you say you had the thing worked out some time ago :roll: 

In any case Marc, if what R4 has posted for you does the job by all means use it.

However, just to finish what I started, here's the modified version of my first example (when I didn't really understand what you wanted). The following version defers the kill notes until you start another 'phrase' after lifting all the keys (at least I think that's what you wanted).

*on init*
``message('')
``*declare* held_note_count
``*declare* latched_note_count
``*declare* mark := 2```_{ toggle this between 2 & 4 }_
``*declare* current_mark
``current_mark := mark
``*declare* ui_button Stop``_{ stopped latched notes }_
````set_text(Stop,'Kill Latched Notes')
*end* on

*on note*
``ignore_event(EVENT_ID)
``*if* held_note_count = 0
````toggle_mark
````note_off(by_marks(current_mark))
````held_note_count := latched_note_count
````latched_note_count := 0
``*end* *if*
``set_event_mark(play_note(EVENT_NOTE,EVENT_VELOCITY,0,0),mark)
``inc(latched_note_count)
``inc(held_note_count)
``current_mark := mark
*end* on

*on release*
``dec(held_note_count)
*end* on

*on ui_control*(Stop)
``Stop := 0
``*if* held_note_count = 0``
````note_off(ALL_EVENTS)
````held_note_count := latched_note_count
````latched_note_count := 0
``*end* *if*
*end* on

*function* toggle_mark
``*if* mark = 2
````mark := 4
``*else*
````mark := 2
``*end* *if*
*end* *function*


There are several ways you can accomplish the Kill all prior notes. In my example I do it by marking alternate phrases with MARK_1 and MARK_2 (2 and 4). Please note that the Kill Latched Notes function only works when all keys are released.

Rejoice,

Bob

BTW This example is not intended to be a finished script, I'm just trying to illustrate one way it could be done.


----------



## Raptor4 (Aug 28, 2012)

> I thought you were the first poster asking how to do this and here you say you had the thing worked out some time ago


Hi Bob,
It was a mater of time to solve my own question - bear in mind I have been declared my first UI knob in January this year so my KSP skills are 8 months old!
Thanks to You and the Great teachers here I could come into the deep KSP :shock: !
Regarding the True Midi Latch...
I'm quite familiar with Midi Environments and specially Logic Environment where I spent more than 20 years solving questions like the True Midi Latch etc.
There is a difference between the "True Midi Latch" (which is based on the Hardware Intelligent Synth Workstations) and the Kontakt factory Midi Latch and Spectrasonics Omnisphere (for example) which are nothing more than a toggle key latch utilities.
There was a dispute regarding the Omnisphere latch function some time ago so you can have a look at my prepositions as well as at my the Logic Global "Multi Timbral True Midi Latch" tool. There is a non voice Demo video where I demonstrate it. Here is the forum http://www.northernsounds.com/forum/showthread.php/77261-Omnisphere-would-love-to-see-a-simple-update-for-latch-mode/page2 (LINK).
Regarding your version (*I put my hat in front of you* o-[][]-o ) I just tested it and found out a little problem. If some of my fingers are still holding a key then there is a mess with the new notes - i.e the previous notes are not killed. In the "True Midi Latch" you have to be able to play any order, any hold down, polyphonic melodies and there be no "sustaining notes" etc. To my opinion All Notes OFF will get more CPU when you need just to kill 1-2 notes. In my version I use All Notes OFF as global panic when disable the "Latch" button, but all the time I use another scheme (the "Clutch KS") which kills the currently playing notes only! 
Anyway your version will be my tomorrow self-teaching material !
Regards,

Ivan


----------



## Big Bob (Aug 28, 2012)

Hi Ivan,



> Regarding your version (I put my hat in front of you ) I just tested it and found out a little problem. If some of my fingers are still holding a key then there is a mess with the new notes - i.e the previous notes are not killed.



My example script only works that way because it was what Marc asked for :lol: At least as understood by me :roll: 

Understand first of all, that I know nothing about the ancestor of this function that may have existed in any DAW hardware or software. Which I tried to say in my first post. I was merely trying to suggest a way to implement what Marc seemed to be trying to work out. I didn't intend my humble offering as some kind of 'finished' scripting effort. :lol: 

I sure hope that I didn't step on anyone's toes here, I was merely trying to implement the function as well as it had been explained. Evidently there is much more to it than what was said and that may be well understood by anyone familiar with the original hardware version.



> In my version I use All Notes OFF as global panic when disable the "Latch" button, but all the time I use another scheme (the "Clutch KS") which kills the currently playing notes only!



I must confess that I haven't had time to study what you posted but I will point out that I didn't use All Notes OFF either, I used 'clear all prior sounding notes' whenever starting a new phrase (by using marks to keep track of alternating phrases ie chords).



> bear in mind I have been declared my first UI knob in January this year so my KSP skills are 8 months old!



Kudos for that. I think very few newby scripters have as deep an understanding as you seem to have, so hat's off to R4. As I said previously, I hope I didn't say something offensive. And now, I better get back to finishing up WIPS.

God Bless,

Bob


----------



## Raptor4 (Aug 28, 2012)

> God Bless


God Bless You as well Master Bob!
I see all you said above. I wish you all the best!
Thanks !

Ivan


----------



## marcmichaelmueller (Aug 29, 2012)

Awesome guys, simply awesome! =o 

Gonna play a bit with those two solutions today 


Regards

Marc


----------



## marcmichaelmueller (Aug 29, 2012)

Now I did a little bit of testing...

for some reason Razor's script won't work on my piano or organ sounds /shrug
it works well on Strings,Synths etc. tho

What I like on Bob's script is that I can still add notes to the chord while only keeping one of the previous keys held down. I can build enormous chords that way just by letting my hand wander over all the ocatves :wink: 

I initially had a problem where sometimes the script wouldn't recognize the note off on the new latch. And sometimes it was like only working right after switching the script on for the second time. That is what I came up with atm. which seems to work 99% the way I want it to:


```
{Advanced Latch by BigBob of VI-Control-Forum}

on init
  set_script_title("Adv Latch")
  message("")
  declare $held_note_count := 0
  declare $latched_note_count
  declare $mark := 2
  declare $current_mark
  $current_mark := $mark
  declare ui_button $Stop
  set_control_par_str(get_ui_id($Stop),$CONTROL_PAR_TEXT,"Kill Latched Notes")
  declare ui_switch $LatchMode
  set_control_par_str(get_ui_id($LatchMode),$CONTROL_PAR_TEXT,"Latch Mode")
  make_persistent($LatchMode)
end on

on note
    if ($LatchMode = 0)
        exit
    else
      ignore_event($EVENT_ID)
      if ($held_note_count=0)
        if ($mark=2)
          $mark := 4
        else
          $mark := 2
        end if
        note_off(by_marks($current_mark))
        $held_note_count := $latched_note_count
        $latched_note_count := 0
      end if
      set_event_mark(play_note($EVENT_NOTE,$EVENT_VELOCITY,0,0),$mark)
      inc($latched_note_count)
      inc($held_note_count)
      $current_mark := $mark
    end if
end on

on release
    if ($held_note_count<1)
        exit
    else
      dec($held_note_count)
    end if
end on

on ui_control($Stop)
  $Stop := 0
  if ($held_note_count=0)
    note_off($ALL_EVENTS)
    $held_note_count := $latched_note_count
    $latched_note_count := 0
  end if
end on

on ui_control($LatchMode)
    select ($LatchMode)
    case 0
      $Stop := 0
        note_off($ALL_EVENTS)
        $held_note_count := $latched_note_count
        $latched_note_count := 0
    case 1
    end select
end on
```

One thing I still would like to do is to only "note off" the previous latched notes when i untic the "Latch Mode"-Switch and the pressed keys still keep ringing as usual.

...anyway thanks a bunch on you two this is already helping me BIG TIME! /\~O

regards

Marc

_________
edit**

For some reason the auto-"Note Off" by enganging a new chord won't work if I use Bob's Script on a second, layered instrument (like Piano+Strings). What does the trick is to load Razor's script to the Strings (since it doesn't work well for me on the piano anyhow)...

Well if the bug with the 2nd instanced instrument and the button behaviour (mentioned above) would be fixed it was abolutely perfect


----------



## Big Bob (Aug 29, 2012)

Hi Marc,



> Well if the bug with the 2nd instanced instrument and the button behaviour (mentioned above) would be fixed it was abolutely perfect



Well afterall, we need to leave something for you to do. :lol: 

I was only trying to give you some ideas to get you started, the rest is up to you :wink: 

I will however mention one refinement you can make to simplify the toggle_mark function. I posted it in a way that would be easier to follow but there is a more efficient way to toggle mark between 2 and 4 without the need for the if-else construct.

mark := 6 - mark

Think about it :roll: 

Rejoice,

Bob


----------



## Raptor4 (Aug 29, 2012)

Hi Marc,
The only thing which can mess my script is CC123 "All Notes Off" . Some hardware devices send CC123 when no key is pressed. This is just an info. 
Can you provide more information about the piano or the organ sounds problem - what happens ?
Here is the update where I have inserted a CC123 filter. As a whole my script is tested to work in any scenario in 100%... My long midi environment design experience showed that using any counters with True Midi Latch can not work in 100% and always cause some problems. The only way is to use a condition note register mapper and kill the notes according that mapper etc.
BTW: Are there any other KSPs in your piano or organ instruments ? This can be a problem as well... If yes, change the KSP order and place my script on the first slot, so it can behave as input one.
Here is the CC123 update:

```
{***********************************************
True Midi Latch v2.0
Author: www.audiogrocery.com
Written by: Ivan Kovachev 
Modified: August 30, 2012
*************************************************}
on init
  make_perfview
  message("AUDIOGROCERY TM")
  set_script_title("True Latch")
  declare $n_num
  declare %note_reg[128]
  declare %note_id[128]
  declare $ks_Lt4_res
  declare ui_switch $Latch
  make_persistent($Latch)
  declare ui_value_edit $clutch_ks(0, 127, 0) 
  make_persistent($clutch_ks)
  _read_persistent_var($clutch_ks)
end on

on controller
if($CC_NUM=123)
ignore_controller
end if
end on

on ui_control($Latch)
  if ($Latch=0)
    note_off($ALL_EVENTS)
  end if
end on

on ui_control($clutch_ks)
  $ks_Lt4_res := 0
  while ($ks_Lt4_res<127)
    set_key_color($ks_Lt4_res,$KEY_COLOR_NONE)
    inc($ks_Lt4_res)
  end while
  set_key_color($clutch_ks,$KEY_COLOR_BLACK)
end on

on note
  if ($Latch=1 and ($EVENT_NOTE # $clutch_ks))
    ignore_event($EVENT_ID)
    $n_num := search(%note_reg,1)
    while ($n_num # -1)
      note_off(%note_id[$n_num])
      %note_reg[$n_num] := 0
      $n_num := search(%note_reg,1)
    end while
    %note_id[$EVENT_NOTE] := play_note($EVENT_NOTE,$EVENT_VELOCITY,0,-1)
  end if
  if ($EVENT_NOTE=$clutch_ks)
    ignore_event($EVENT_ID)
    $n_num := search(%note_reg,1)
    while ($n_num # -1)
      note_off(%note_id[$n_num])
      %note_reg[$n_num] := 0
      $n_num := search(%note_reg,1)
    end while
  end if
end on

on release
  if ($Latch=1)
    ignore_event($EVENT_ID)
    %note_reg[$EVENT_NOTE] := 1
  end if
end on
```
 
Regards,

R4


----------

