A True (Sampled) Legato Script for Kontakt
FOREWORD
Making a virtual instrument sound like a real one has always been a tough job for programmers. Arguably the most challenging part of that job is to make true legato transitions. Putting aside the immense amount of slavery-like work of recording all the possible note transitions within the range of the instrument, one should not underestimate the extraordinarily demanding part of coding that makes it possible for the playback to instantly work according to the intervals of consecutively played notes.
Kontakt is a gift to humanity. Given its programming facility, it is technically possible to create any desired virtual instrument for not only the professionals, but also for any dedicated enthusiast. Its KSP Manual along with dozens of open source courses make it possible to code for even the novice programmer. But once one desires to produce an advance instrument, that's when one starts stumbling.
That is a controversial one but I take what I get. True legato is arguably the number one thing to make an advanced instrument. But none of the so called "FREE & COMPLETE" courses of Kontakt shows how to code a true legato program in Kontakt Script Processor. Despite my hours of days of research, I have found no open source user-friendly true legato script except that of Oscar Chamorro written specifically for VSL Cube samples and work with key-switches. It feels like everyone is gatekeeping with such a motivation as "I have struggled. You must, too.". Or they might find it too precious to give it for no charge. But this is INTERNET and everything has a first. Hence I am proud to be.
This is not a completed project. As I add new features, I am going to update this post.
Performance View of The Instrument with The Script |
THE SCRIPT
make_perfview
set_ui_height(4)
declare ui_slider $repetition_time (0,250)
set_control_par(get_ui_id($repetition_time),$CONTROL_PAR_DEFAULT_VALUE,200)
$repetition_time:=200
make_persistent($repetition_time)
declare ui_label $repetition_time_label(2,1)
set_text($repetition_time_label," REPETITION OFFSET")
declare ui_label $repetition_time_label_variable(1,1)
set_text($repetition_time_label_variable,$repetition_time&"ms")
declare ui_slider $fade_time (0,500000)
set_control_par(get_ui_id($fade_time),$CONTROL_PAR_DEFAULT_VALUE,150000)
$fade_time := 150000
make_persistent($fade_time)
declare ui_label $fade_time_label(2,1)
set_text($fade_time_label," LEGATO FADE TIME")
declare ui_label $fade_time_label_variable(1,1)
set_text($fade_time_label_variable,$fade_time/1000&"ms")
declare ui_slider $fade_time_release (0,200000)
set_control_par(get_ui_id($fade_time_release),$CONTROL_PAR_DEFAULT_VALUE,50000)
$fade_time_release := 50000
make_persistent($fade_time_release)
declare ui_label $fade_time_release_label(2,1)
set_text($fade_time_release_label," RELEASE FADE TIME")
declare ui_label $fade_time_release_label_variable(1,1)
set_text($fade_time_release_label_variable,$fade_time_release/1000&"ms")
declare ui_slider $fade_time_repetition (0,250000)
set_control_par(get_ui_id($fade_time_repetition),$CONTROL_PAR_DEFAULT_VALUE,0)
$fade_time_repetition := 0
make_persistent($fade_time_repetition)
declare ui_label $fade_time_repetition_label(2,1)
set_text($fade_time_repetition_label," REPETITON FADE TIME")
declare ui_label $fade_time_repetition_label_variable(1,1)
set_text($fade_time_repetition_label_variable,$fade_time_repetition/1000&"ms")
declare ui_button $reset_rep_time
set_text($reset_rep_time,"SET DEFAULT")
declare ui_button $reset_leg_time
set_text($reset_leg_time,"SET DEFAULT")
declare ui_button $reset_rls_time
set_text($reset_rls_time,"SET DEFAULT")
declare ui_button $reset_repf_time
set_text($reset_repf_time,"SET DEFAULT")
move_control($repetition_time,3,3)
move_control($repetition_time_label,1,3)
move_control($repetition_time_label_variable,4,3)
move_control($fade_time,3,4)
move_control($fade_time_label,1,4)
move_control($fade_time_label_variable,4,4)
move_control($fade_time_release,3,5)
move_control($fade_time_release_label,1,5)
move_control($fade_time_release_label_variable,4,5)
move_control($fade_time_repetition,3,6)
move_control($fade_time_repetition_label,1,6)
move_control($fade_time_repetition_label_variable,4,6)
move_control($reset_rep_time,5,3)
move_control($reset_leg_time,5,4)
move_control($reset_rls_time,5,5)
move_control($reset_repf_time,5,6)
declare $last_id
declare $interval
declare $note_counter := 0
declare $temp_note_counter
declare $temp_id
declare $last_time_release
declare $last_time_note
declare $menu_switch:= 0
declare $legato_switch:= 0
declare $counter := 0
declare %downkeys[10]
declare !intervals[25]
!intervals[0] := "-12"
!intervals[1] := "-11"
!intervals[2] := "-10"
!intervals[3] := "-9"
!intervals[4] := "-8"
!intervals[5] := "-7"
!intervals[6] := "-6"
!intervals[7] := "-5"
!intervals[8] := "-4"
!intervals[9] := "-3"
!intervals[10] := "-2"
!intervals[11] := "-1"
!intervals[12] := "0"
!intervals[13] := "+1"
!intervals[14] := "+2"
!intervals[15] := "+3"
!intervals[16] := "+4"
!intervals[17] := "+5"
!intervals[18] := "+6"
!intervals[19] := "+7"
!intervals[20] := "+8"
!intervals[21] := "+9"
!intervals[22] := "+10"
!intervals[23] := "+11"
!intervals[24] := "+12"
end on
{**********}
on note
$last_id := $EVENT_ID
ignore_event($ALL_EVENTS)
inc($note_counter)
$last_time_note := $ENGINE_UPTIME
$counter := num_elements(%downkeys)-1
while ($counter > 0)
%downkeys[$counter] := %downkeys[$counter-1]
dec($counter)
end while
%downkeys[0] := $EVENT_NOTE
{message("#of notes:"&$note_counter)}
message(%downkeys[0]&" "&%downkeys[1]&" "&%downkeys[2]&" "&%downkeys[3]&" "&%downkeys[4]&" "&%downkeys[5])
if ($note_counter = 1)
disallow_group($ALL_GROUPS)
if ($ENGINE_UPTIME < $last_time_release + $repetition_time)
allow_group(find_group("0"))
else
allow_group(find_group("start"))
end if
play_note($EVENT_NOTE,$EVENT_VELOCITY,0,0)
else
fade_out($ALL_EVENTS,$fade_time,1)
disallow_group($ALL_GROUPS)
if ($EVENT_NOTE-%downkeys[1] < 13 and $EVENT_NOTE-%downkeys[1] > -13)
allow_group(find_group(!intervals[$EVENT_NOTE-%downkeys[1]+12]))
else
allow_group(find_group("start"))
end if
fade_in(play_note($EVENT_NOTE,$EVENT_VELOCITY,0,0),$fade_time)
end if
end on
{**********}
on release
ignore_event($ALL_EVENTS)
dec($note_counter)
$last_time_release := $ENGINE_UPTIME
{message("#of notes:"&$note_counter)}
message(%downkeys[0]&" "&%downkeys[1]&" "&%downkeys[2]&" "&%downkeys[3]&" "&%downkeys[4]&" "&%downkeys[5])
if ($note_counter = 0)
fade_out($ALL_EVENTS,$fade_time_release,1)
disallow_group($ALL_GROUPS)
allow_group(find_group("release"))
fade_in(play_note($EVENT_NOTE,$EVENT_VELOCITY,0,0),$fade_time_release)
$counter := search(%downkeys,$EVENT_NOTE)
while ($counter < num_elements(%downkeys))
%downkeys[$counter] := %downkeys[$counter+1]
inc($counter)
end while
else
if ($EVENT_NOTE = %downkeys[0])
fade_out($ALL_EVENTS,$fade_time,1)
disallow_group($ALL_GROUPS)
if ($EVENT_NOTE-%downkeys[1] < 13 and $EVENT_NOTE-%downkeys[1] > -13)
allow_group(find_group(!intervals[%downkeys[1]-$EVENT_NOTE+12]))
else
allow_group(find_group("start"))
end if
fade_in(play_note(%downkeys[1],$EVENT_VELOCITY,0,0),$fade_time)
$counter := search(%downkeys,$EVENT_NOTE)
while ($counter < num_elements(%downkeys))
%downkeys[$counter] := %downkeys[$counter+1]
inc($counter)
end while
else
$counter := search(%downkeys,$EVENT_NOTE)
while ($counter < num_elements(%downkeys))
%downkeys[$counter] := %downkeys[$counter+1]
inc($counter)
end while
end if
end if
message(%downkeys[0]&" "&%downkeys[1]&" "&%downkeys[2]&" "&%downkeys[3]&" "&%downkeys[4]&" "&%downkeys[5])
end on
{**********}
on ui_control($repetition_time)
set_text($repetition_time_label_variable,$repetition_time&"ms")
end on
on ui_control($fade_time)
set_text($fade_time_label_variable,$fade_time/1000&"ms")
end on
on ui_control($fade_time_release)
set_text($fade_time_release_label_variable,$fade_time_release/1000&"ms")
end on
on ui_control($fade_time_repetition)
set_text($fade_time_repetition_label_variable,$fade_time_repetition/1000&"ms")
end on
on ui_control($reset_rep_time)
$repetition_time := 200
set_text($repetition_time_label_variable,$repetition_time&"ms")
end on
on ui_control($reset_leg_time)
$fade_time := 150000
set_text($fade_time_label_variable,$fade_time/1000&"ms")
end on
on ui_control($reset_rls_time)
$fade_time_release := 50000
set_text($fade_time_release_label_variable,$fade_time_release/1000&"ms")
end on
on ui_control($reset_repf_time)
$fade_time_repetition := 0
set_text($fade_time_repetition_label_variable,$fade_time_repetition/1000&"ms")
end on