KONTAKT - Humanizer script for each group

Sampler and Sampling discussion (techniques, tips and tricks, etc.)
Post Reply New Topic
RELATED
PRODUCTS
Kontakt

Post

Hi world!

I've created a script (starting from the script "Humanizer" from Kontakt's preset factory) that allow to set different values to each group. It works great, except when its on a instrument which notes triggers two or more groups at the same time, like on the drum kit "Vintake Kit" of the NI Factory content (or any other multi layer with overheads and room). On that drum kit, it only happen with notes C1 and D1, since those are the only ones that triggers two groups at once (group 0 "bass drum 1" and group 1 "bass drum 3" for the bd, and group 2 "snare 1" and group 11 "snare 2" for the snare). If the shift key is pressed while moving a knob, the script applies the value to all the groups, and then the snare or the bass drum sound wrong, like when two samples of the same sound are played in unison :(

Here's the script:

Code: Select all

on init
	make_perfview

	declare $count

	declare ui_knob $group (0,$NUM_GROUPS-1,1)
		set_control_par_str(get_ui_id($group),$CONTROL_PAR_TEXT, group_name($group))
		make_persistent($group)
		read_persistent_var($group)

	declare %human_gtime[128]
		make_persistent(%human_gtime)
		read_persistent_var(%human_gtime)
	declare ui_knob $hum_time(0,100,1)
		set_text($hum_time,"Timing")
		make_persistent($hum_time)
		read_persistent_var($hum_time)

	declare %human_gvel[128]
		make_persistent(%human_gvel)
		read_persistent_var(%human_gvel)
	declare ui_knob $hum_vel(0,100,1)
		set_text($hum_vel,"Velocity")
		make_persistent($hum_vel)
		read_persistent_var($hum_vel)

	declare %human_gtune[128]
		make_persistent(%human_gtune)
		read_persistent_var(%human_gtune)
	declare ui_knob $hum_tune(0,100,1)
		set_text($hum_tune,"Tuning")
		make_persistent($hum_tune)
		read_persistent_var($hum_tune)

	declare %human_gvol[128]
		make_persistent(%human_gvol)
		read_persistent_var(%human_gvol)
	declare ui_knob $hum_vol(0,100,1)
		set_text($hum_vol,"Volume")
		make_persistent($hum_vol)
		read_persistent_var($hum_vol)

	declare $new_time
	declare $new_vel
	declare $new_tune
	declare $new_vol
	declare $new_event
	declare $shift
end on



on note
	$count := 0
	while ($count < num_elements(%GROUPS_AFFECTED))
		ignore_event($EVENT_ID)

		$new_time := random(0,%human_gtime[%GROUPS_AFFECTED[$count]] * 1000)
		$new_vel := $EVENT_VELOCITY + (random(-127,127) * %human_gvel[%GROUPS_AFFECTED[$count]] / 200)

		$new_tune := random(-1000,1000) * %human_gtune[%GROUPS_AFFECTED[$count]]
		$new_vol := random(-60,60) * %human_gvol[%GROUPS_AFFECTED[$count]]

		if (in_range($new_vel,0,127))
			$new_vel := $new_vel
		else
			if ($new_vel > 127)
				$new_vel := 127
			end if
			if ($new_vel < 1)
				$new_vel := 1
			end if
		end if

		wait($new_time+1)
		$new_event := play_note($EVENT_NOTE, $new_vel, 0, -1)
		change_tune($new_event, $new_tune, 1)
		change_vol($new_event, $new_vol, 1)

		inc($count)
	end while

	message("")
end on


on ui_control($group)
	$hum_time := %human_gtime[$group]
	$hum_vel := %human_gvel[$group]
	$hum_tune := %human_gtune[$group]
	$hum_vol := %human_gvol[$group]
	set_control_par_str(get_ui_id($group),$CONTROL_PAR_TEXT, group_name($group))
end on

on ui_control($hum_time)
	$shift := get_control_par(get_ui_id($hum_time),$CONTROL_PAR_KEY_SHIFT)
	if ($shift = 1)
		$count := 0
		while ($count < $NUM_GROUPS)
			%human_gtime[$count] := $hum_time
			inc($count)
		end while
	else
		%human_gtime[$group] := $hum_time
	end if
end on

on ui_control($hum_vel)
	$shift := get_control_par(get_ui_id($hum_vel),$CONTROL_PAR_KEY_SHIFT)
	if ($shift = 1)
		$count := 0
		while ($count < $NUM_GROUPS)
			%human_gvel[$count] := $hum_vel
			inc($count)
		end while
	else
		%human_gvel[$group] := $hum_vel
	end if
end on

on ui_control($hum_tune)
	$shift := get_control_par(get_ui_id($hum_tune),$CONTROL_PAR_KEY_SHIFT)
	if ($shift = 1)
		$count := 0
		while ($count < $NUM_GROUPS)
			%human_gtune[$count] := $hum_tune
			inc($count)
		end while
	else
		%human_gtune[$group] := $hum_tune
	end if
end on

on ui_control($hum_vol)
	$shift := get_control_par(get_ui_id($hum_vol),$CONTROL_PAR_KEY_SHIFT)
	if ($shift = 1)
		$count := 0
		while ($count < $NUM_GROUPS)
			%human_gvol[$count] := $hum_vol
			inc($count)
		end while
	else
		%human_gvol[$group] := $hum_vol
	end if
end on

Any help will be appreciated. Cheers.

Post

hellishvictor wrote: Tue Jun 25, 2019 4:49 pm the snare or the bass drum sound wrong, like when two samples of the same sound are played in unison :(
Which is exactly what happens. If the note affects say groups 1 and 2, this script ignores initial note and plays two new notes with randomized parameters, but each of two new notes affects both groups so the voice number doubles. You should send each of new notes to one group only. Like...

Code: Select all

set_event_par_arr($new_event,$EVENT_PAR_ALLOW_GROUP,0,$ALL_GROUPS)
set_event_par_arr($new_event,$EVENT_PAR_ALLOW_GROUP,1,%GROUPS_AFFECTED[$count])
But your main problem in the script is the wait command. This will freeze the script on current group in the while cycle. Suppose you have group 1 and group 2, you want to add random delay to group 1 but not to group 2. This is not possible with your script. If group 1 is delayed, all the following groups get the same delay, plus their own delay. Also if you play a chord and you get different note packets with different delays it will mess it all up, as you use single variable "$count" for all notes, so $count should be polyphonic variable here.
Distributing delays in this situation is not a trivial task, you should calculate all the delays beforehand, order them and split the times, so the notes with shortest delay play first. And do all that with polyphonic variables, so callbacks for different notes being processed in parallel will not interfere with each other changing the variables. :borg:

Post

Thank you Zombie Queen! Later at home I'll try that out.

Post

Well, I've declare $count as polyphonic and now when I try to play a global setting to a control using the shift key on it, the values only applies to the actual group and shows the following message:

SCRIPT WARNING: while loop terminated (too much iterations, no wait statement)

If $shift is declared as polyphonic the message dissapear, however, the behaviour is the same; it only affect to the actual group, not to all.

Code: Select all

on init
	make_perfview

	declare polyphonic $count

	declare ui_knob $group (0,$NUM_GROUPS-1,1)
		set_control_par_str(get_ui_id($group),$CONTROL_PAR_TEXT, group_name($group))
		make_persistent($group)
		read_persistent_var($group)

	declare %human_gtime[128]
		make_persistent(%human_gtime)
		read_persistent_var(%human_gtime)
	declare ui_knob $hum_time(0,100,1)
		set_text($hum_time,"Timing")
		make_persistent($hum_time)
		read_persistent_var($hum_time)

	declare %human_gvel[128]
		make_persistent(%human_gvel)
		read_persistent_var(%human_gvel)
	declare ui_knob $hum_vel(0,100,1)
		set_text($hum_vel,"Velocity")
		make_persistent($hum_vel)
		read_persistent_var($hum_vel)

	declare %human_gtune[128]
		make_persistent(%human_gtune)
		read_persistent_var(%human_gtune)
	declare ui_knob $hum_tune(0,100,1)
		set_text($hum_tune,"Tuning")
		make_persistent($hum_tune)
		read_persistent_var($hum_tune)

	declare %human_gvol[128]
		make_persistent(%human_gvol)
		read_persistent_var(%human_gvol)
	declare ui_knob $hum_vol(0,100,1)
		set_text($hum_vol,"Volume")
		make_persistent($hum_vol)
		read_persistent_var($hum_vol)

	declare $new_time
	declare $new_vel
	declare $new_tune
	declare $new_vol
	declare $new_event
	declare polyphonic $shift
end on



on note
	$count := 0
	while ($count < num_elements(%GROUPS_AFFECTED))
		ignore_event($EVENT_ID)

		$new_time := random(0,%human_gtime[%GROUPS_AFFECTED[$count]] * 1000)
		$new_vel := $EVENT_VELOCITY + (random(-127,127) * 		%human_gvel[%GROUPS_AFFECTED[$count]] / 200)

		$new_tune := random(-1000,1000) * %human_gtune[%GROUPS_AFFECTED[$count]]
		$new_vol := random(-60,60) * %human_gvol[%GROUPS_AFFECTED[$count]]

		if (in_range($new_vel,0,127))
			$new_vel := $new_vel
		else
			if ($new_vel > 127)
				$new_vel := 127
			end if
			if ($new_vel < 1)
				$new_vel := 1
			end if
		end if

		wait($new_time+1)
		$new_event := play_note($EVENT_NOTE, $new_vel, 0, -1)
		set_event_par_arr($new_event,$EVENT_PAR_ALLOW_GROUP,0,$ALL_GROUPS)
		set_event_par_arr($new_event,$EVENT_PAR_ALLOW_GROUP,1,%GROUPS_AFFECTED[$count])
		change_tune($new_event, $new_tune, 1)
		change_vol($new_event, $new_vol, 1)

		inc($count)
	end while

	message("")
end on


on ui_control($group)
	$hum_time := %human_gtime[$group]
	$hum_vel := %human_gvel[$group]
	$hum_tune := %human_gtune[$group]
	$hum_vol := %human_gvol[$group]
	set_control_par_str(get_ui_id($group),$CONTROL_PAR_TEXT, group_name($group))
end on

on ui_control($hum_time)
	$shift := get_control_par(get_ui_id($hum_time),$CONTROL_PAR_KEY_SHIFT)
	if ($shift = 1)
		$count := 0
		while ($count < $NUM_GROUPS)
			%human_gtime[$count] := $hum_time
			inc($count)
		end while
	else
		%human_gtime[$group] := $hum_time
	end if
end on

on ui_control($hum_vel)
	$shift := get_control_par(get_ui_id($hum_vel),$CONTROL_PAR_KEY_SHIFT)
	if ($shift = 1)
		$count := 0
		while ($count < $NUM_GROUPS)
			%human_gvel[$count] := $hum_vel
			inc($count)
		end while
	else
		%human_gvel[$group] := $hum_vel
	end if
end on

on ui_control($hum_tune)
	$shift := get_control_par(get_ui_id($hum_tune),$CONTROL_PAR_KEY_SHIFT)
	if ($shift = 1)
		$count := 0
		while ($count < $NUM_GROUPS)
			%human_gtune[$count] := $hum_tune
			inc($count)
		end while
	else
		%human_gtune[$group] := $hum_tune
	end if
end on

on ui_control($hum_vol)
	$shift := get_control_par(get_ui_id($hum_vol),$CONTROL_PAR_KEY_SHIFT)
	if ($shift = 1)
		$count := 0
		while ($count < $NUM_GROUPS)
			%human_gvol[$count] := $hum_vol
			inc($count)
		end while
	else
		%human_gvol[$group] := $hum_vol
	end if
end on
Zombie Queen wrote: Wed Jun 26, 2019 1:51 pm Distributing delays in this situation is not a trivial task, you should calculate all the delays beforehand, order them and split the times, so the notes with shortest delay play first.
I think I need help :cry:

Post

Distributing delay times works something like this:

https://www.native-instruments.com/foru ... st-1543506

Post

Thank you for the link, EviDragon

Post

hellishvictor wrote: Wed Jun 26, 2019 10:03 pm it only affect to the actual group, not to all
Are you sure you want different humanization range per group? Looks to me like you may want to set it per note. With a drum machine when a note triggers two samples, you want second sample to be "humanized" differently, or same as the first one?

There's excellent graphic in Evil Dragon's post showing the distribution of delay times. If you want to cheat and have another script slot empty, and event parameters not used, you can pass the waiting to be done in another script.

Code: Select all

{the main script fragment}

$note_id := play_note($note_number, $note_velocity, 0, $note_duration)

if($note_delay #0)
	set_event_par($note_id, $EVENT_PAR_3, $note_delay) {mark note as delayed}
	set_event_par($note_id, $EVENT_PAR_2, $note_duration)
end if

{....}

{the other script fragment}
on note
	
	if(get_event_par($EVENT_ID,$EVENT_PAR_2) >0 and get_event_par($EVENT_ID,$EVENT_PAR_3) >0) {delay marked notes}
	
		ignore_event($EVENT_ID)
		wait(get_event_par($EVENT_ID,$EVENT_PAR_3))
		$new_id := play_note($EVENT_NOTE,$EVENT_VELOCITY,0,get_event_par($EVENT_ID,$EVENT_PAR_2))
		
		change_pan($new_id,get_event_par($EVENT_ID,$EVENT_PAR_PAN),0)
		change_tune($new_id,get_event_par($EVENT_ID,$EVENT_PAR_TUNE),0)
		change_vol($new_id,get_event_par($EVENT_ID,$EVENT_PAR_VOLUME),0)
		
		{copy group assignments}
		$count := 0
		while($count < $NUM_GROUPS)
			set_event_par_arr($new_id,$EVENT_PAR_ALLOW_GROUP,get_event_par_arr($EVENT_ID,$EVENT_PAR_ALLOW_GROUP,$count),$count)
			inc($count)
		end while
	end if
end on

{...}
In which case each note is being given a separate callback in the other script, where it can be easily delayed. So Kontakt does all the work. Just note that the "other script" must be inserted after the main one.

Post

Zombie Queen wrote: Thu Jun 27, 2019 12:53 pm Are you sure you want different humanization range per group? Looks to me like you may want to set it per note. With a drum machine when a note triggers two samples, you want second sample to be "humanized" differently, or same as the first one?
Yeah, same as the first one! If several groups use the same note, they should have the same random time; in a multi layer kit, a note triggers the dry but also the room and overheads. I just gonna use for drums. For me everything went well with the other drum kits till that I use the script with multi-layer kits and started to sound wrong with the duplicated sound. I gonna try your codes and see how it goes, because now I have a huge headache :cry:

Post

hellishvictor wrote: Thu Jun 27, 2019 4:00 pmYeah, same as the first one! If several groups use the same note, they should have the same random time; in a multi layer kit...
Then you are biting it from the wrong end. Make the parameters definable for each note separately, not for each group. Then in note callback you don't need the while loop to trigger multiple notes (a separate note for each group) and you don't need to worry about delay distribution, since there will be only one delay and one note.

Post

Done :)

Code: Select all

on init
	make_perfview
	set_script_title("Humanize Notes")

	declare $count

	declare !note[12]
		!note[0] := "C"
		!note[1] := "Db"
		!note[2] := "D"
		!note[3] := "Eb"
		!note[4] := "E"
		!note[5] := "F"
		!note[6] := "Gb"
		!note[7] := "G"
		!note[8] := "Ab"
		!note[9] := "A"
		!note[10] := "Bb"
		!note[11] := "B"

	declare !name [128]

	while ($count < 128)
		!name[$count] := !note[$count mod 12] & (($count/12)-2)
		inc ($count)
	end while

	declare ui_switch $bymidi
		set_text($bymidi, "Set with MIDI")
		$bymidi := 1
		make_persistent($bymidi)
		read_persistent_var($bymidi)

	declare ui_knob $actual_note(0,127,1)
		$actual_note := 36
		make_persistent($actual_note)
		read_persistent_var($actual_note)
		set_text($actual_note, !name[$actual_note])
		move_control($actual_note, 1, 2)

	declare %human_time[128]
		make_persistent(%human_time)
		read_persistent_var(%human_time)
	declare ui_knob $hum_time(0,100,1)
		set_knob_unit($hum_time, $KNOB_UNIT_PERCENT)
		set_text($hum_time,"Timing")
		make_persistent($hum_time)
		read_persistent_var($hum_time)

	declare %human_vel[128]
		make_persistent(%human_vel)
		read_persistent_var(%human_vel)
	declare ui_knob $hum_vel(0,100,1)
		set_text($hum_vel,"Velocity")
		set_knob_unit($hum_vel, $KNOB_UNIT_PERCENT)
		make_persistent($hum_vel)
		read_persistent_var($hum_vel)

	declare %human_tune[128]
		make_persistent(%human_tune)
		read_persistent_var(%human_tune)
	declare ui_knob $hum_tune(0,100,1)
		set_text($hum_tune,"Tuning")
		set_knob_unit($hum_tune, $KNOB_UNIT_PERCENT)
		make_persistent($hum_tune)
		read_persistent_var($hum_tune)

	declare %human_vol[128]
		make_persistent(%human_vol)
		read_persistent_var(%human_vol)
	declare ui_knob $hum_vol(0,100,1)
		set_text($hum_vol,"Volume")
		set_knob_unit($hum_vol, $KNOB_UNIT_PERCENT)
		make_persistent($hum_vol)
		read_persistent_var($hum_vol)

	declare $new_time
	declare $new_vel
	declare $new_tune
	declare $new_vol
	declare $new_event
	declare $shift
end on


function UPDATE_KNOB
	set_text($actual_note, !name[$actual_note])

	$hum_time := %human_time[$actual_note]
	$hum_vel := %human_vel[$actual_note]
	$hum_tune := %human_tune[$actual_note]
	$hum_vol := %human_vol[$actual_note]
end function


on note
	ignore_event($EVENT_ID)
	if ($bymidi = 1)
		$actual_note := $EVENT_NOTE
		call UPDATE_KNOB
	end if

	$new_time := random(0,%human_time[$EVENT_NOTE] * 1000)
	$new_vel := $EVENT_VELOCITY + (random(-127,127) * %human_vel[$EVENT_NOTE] / 200)
	$new_tune := random(-1000,1000) * %human_tune[$EVENT_NOTE]
	$new_vol := random(-60,60) * %human_vol[$EVENT_NOTE]

	if (in_range($new_vel,0,127))
		$new_vel := $new_vel
	else
		if ($new_vel > 127)
			$new_vel := 127
		end if
		if ($new_vel < 1)
			$new_vel := 1
		end if
	end if

	wait($new_time + 1)
	$new_event := play_note($EVENT_NOTE, $new_vel, 0, -1)
	change_tune($new_event, $new_tune, 1)
	change_vol($new_event, $new_vol, 1)
end on

on ui_control($actual_note)
	call UPDATE_KNOB
end on

on ui_control($hum_time)
	$shift := get_control_par(get_ui_id($hum_time),$CONTROL_PAR_KEY_SHIFT)
	if ($shift = 1)
		$count := 0
		while ($count < 128)
			%human_time[$count] := $hum_time
			inc($count)
		end while
	else
		%human_time[$actual_note] := $hum_time
	end if
end on

on ui_control($hum_vel)
	$shift := get_control_par(get_ui_id($hum_vel),$CONTROL_PAR_KEY_SHIFT)
	if ($shift = 1)
		$count := 0
		while ($count < 128)
			%human_vel[$count] := $hum_vel
			inc($count)
		end while
	else
		%human_vel[$actual_note] := $hum_vel
	end if
end on

on ui_control($hum_tune)
	$shift := get_control_par(get_ui_id($hum_tune),$CONTROL_PAR_KEY_SHIFT)
	if ($shift = 1)
		$count := 0
		while ($count < 128)
			%human_tune[$count] := $hum_tune
			inc($count)
		end while
	else
		%human_tune[$actual_note] := $hum_tune
	end if
end on

on ui_control($hum_vol)
	$shift := get_control_par(get_ui_id($hum_vol),$CONTROL_PAR_KEY_SHIFT)
	if ($shift = 1)
		$count := 0
		while ($count < 128)
			%human_vol[$count] := $hum_vol
			inc($count)
		end while
	else
		%human_vol[$actual_note] := $hum_vol
	end if
end on
Thank you so much Zombie Queen !

Post Reply

Return to “Samplers, Sampling & Sample Libraries”