Welcome!

Murat Yaşar Baskın (born 1998, Turkey) is a music enthusiast.
This is his dedicated website.
Here you can find references to his works,
Read his blog,
Or get in touch with him.
Use the tabs above or the sidebar to see different content.

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


DEFINITIONS
Repetition Offset: Maximum time to trigger repetition samples after releasing a key. Let T be the time difference between releasing and pushing the same key. If T < Repetition Offset, a repetition sample is played back. Else, a start (sustain)  sample is played back.

Legato Fade Time: Overlap time of end of first sample and beginning of the legato sample. When a note is triggered while another note is on, the previous note starts to fade out as legato sample of the triggered note starts to fade in. Legato Fade Time is the time difference between the start and end of those fade outs.

Release Fade Time: Overlap time of end of first sample and beginning of the release sample. When a note is released, the sustain sample starts to fade out as release sample of the triggered note starts to fade in. Release Fade Time is the time difference between the start and end of those fade outs.

Repetition Fade Time: Overlap time of end of first sample and beginning of the repetition sample.

HOW THE SCRIPT WORKS

Group Editor View

The script works through interval groups as shown in the image. All you have to do is to create 24 legato groups (-12 up to +12) for each interval within an octave, with the amount of interval transition as the name of the group (e.g. +12 means one octave up transition, -12 means one octave down transition); a group with the name "0" for repetition samples, a group with the name "start" for start/sustain samples, and a group with the name "release" for release samples. 

THE SCRIPT

on init
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