1. IMPORTANT:
    We launched a new online community and this space is now closed. This community will be available as a read-only resources until further notice.
    JOIN US HERE

Kontakt Script to crossfade between groups?

Discussion in 'Scripting Workshop' started by m3m, Oct 6, 2007.

Thread Status:
Not open for further replies.
  1. m3m

    m3m NI Product Owner

    Messages:
    536
    Hello

    I've just been reading the KSP Manual - there's something I'd like to script; I have a feeling it might not be possible but was wondering if anyone had experience of doing something similar?

    I'd like to make a detailed model of a snare drum. To do this I'd like to have 8 (say) velocity layers for hits of different strengths; and I'd like to use pitch to model distance of hits from the centre of the drum: maybe 4 sets of samples at different distances. I'd like to experiment with velocity and pitch crossfades to blend samples together.

    I'd also like to model whether the drum hit falls on the line of the snare, at 90 degrees to the snare, or half-way in between. I'm calling this the "orientation" of the hit. I effectively need a 3-D sample map. I'm assuming I'll use groups to model this: each group stores a sample map relating to a different orientation.

    What would be really great, though, would be to use a MIDI CC or an LFO to choose an orientation value; and then to crossfade between groups: EG play a sample from Group 1 at -2.5dB and a sample from Group 2 at -2.5dB if MIDI CC says the hit's orientation falls halfway between that of group 1 and group 2.

    Is this possible? It's not a big deal if not, I'm just interested to know how far scripting will go in terms of dealing with groups.
     
  2. kotori

    kotori NI Product Owner

    Messages:
    1,153
    Hi Dave,
    That's definitely possible and not particularily hard to implement either if you have an idea of what groups you want to blend in different situations.

    Here's an example of a very basic script that for each incoming note creates two voices - one using the first group of the instrument and one using the second group - and then mixes them. Since just a simple sample it's always the same pair of groups and always the same volume adjustment, but it's not too hard to add some conditions making it more dynamic. I thought I'd try to give you a feel of what it looks like.

    on init
    ``declare id1``
    ``declare id2
    end on

    on note
    ``{ ignore the incoming note event since we generate our own voices below }
    ``ignore_event(EVENT_ID)
    ``
    ``{ generate a voice with only the first group (index 0) activated }
    ``disallow_group(ALL_GROUPS)
    ``allow_group(0)
    ``id1 := play_note(EVENT_NOTE, EVENT_VELOCITY, 0, -1)
    ``
    ``{ generate a voice with only the second group (index 1) activated }
    ``disallow_group(ALL_GROUPS)
    ``allow_group(1)
    ``id2 := play_note(EVENT_NOTE, EVENT_VELOCITY, 0, -1)
    ``
    ``{ blend the two voices by adjusting their volumes }
    ``change_vol(id1,``2000, 1)```{ turn volume up 2000 millidB }
    ``change_vol(id2, -4000, 1)```{ turn volume down 4000 millidB }
    end on


    If you are interesting in scripting I recommend that you pay a visit to the Kontakt subforum at VI-Control. On that forum there is also a collection of general purpose math routines written by Big Bob which let you easily do equal-power crossfades between voices. Good luck and happy scripting!

    Regards,
    Nils
     
    • Like Like x 1
  3. m3m

    m3m NI Product Owner

    Messages:
    536
    Nils, thanks! I've probably got the wrong conception of how scripts are processed, and the timing of that processing with respect to the audio actually being triggered. Looking at your example for the first time it feels like I'm asking to play a note and then change the volume of a note that's already playing... but I suppose if the script can be considered to run instantaneously, that's just not an issue!

    FWIW, I used Reaktor to figure out a little table of dB values for changing the volume of each group at various points across the crossfade... if I get the script working, I'll post here and let you know how it went.

    Cheers for the forum link - and congratulations on your work for Scarbee, and the tutorial/script examples. Seriously impressive. :)
     
  4. m3m

    m3m NI Product Owner

    Messages:
    536
    Hello there

    Thanks largely to Nils, who saved me between 3 hours' and 3 weeks' work, I got my script working. It sidesteps any clever maths by using a lookup table to calculate volume adjustments for the crossfades... but it does work, so just in case anyone wants to play with it, here it is: a script which plays each note within a random range through a crossfade between three sample groups (imagine a drummer hitting a snare drum in a different position each time...).

    Code:
    on init
    
    	{Knobs to define min, max crossfade pos}
    	declare ui_knob $XFMin(0,127,1)
    	$XFMin := 0
    	declare ui_knob $XFMax(0,127,1)
    	$XFMax := 127
    
    	{Variable for position through crossfade (0 .. 16, 2 = centre)}
    	declare polyphonic $crossfade_pos := 0
    
    	{Array of millidB volume adjustments for channel A at each position through crossfade}
    	declare %crossfade_db[17] := ...
    	(0, -561, -1160, -1804, -2500, -3255, -4082, -4998, -6020, ...
    	-7180, -8519, -10103, -12040, -14540, -18162, -24082, -120000)
    
    	{Variables for IDs of notes played with each channel}
    	declare $note_id_a
    	declare $note_id_b
    
    	{Variables for sample group index for each channel}
    	declare polyphonic $group_idx_a := 0
    	declare polyphonic $group_idx_b := 0
    
    	{Volume of channel A and channel B}
    	declare polyphonic $db_a := 0
    	declare polyphonic $db_b := 0
    
    	{Clear Kontakt status bar}
    	message("")
    
    end on
    
    on ui_control($XFMin)
    	if($XFMin > $XFMax)
    		$XFMax := $XFMin
    	end if
    end on
    
    on ui_control($XFMax)
    	if($XFMin > $XFMax)
    		$XFMin := $XFMax
    	end if
    end on
    
    on note
    
    	$crossfade_pos := random($XFMin, $XFMax)
    
    	{If crossfade pos is <= 63, use sample groups 0 & 1 - else use 0 & 1}
    	$group_idx_a := $crossfade_pos / 64
    	$group_idx_b := $group_idx_a + 1
    
    	{Work out how far in between the groups the crossfade lies}
    	$crossfade_pos := $crossfade_pos mod 64
    	{Turn $crossfade_pos into a number between 0 & 16: the position in the crossfade}
    	$crossfade_pos := $crossfade_pos + 2
    	$crossfade_pos := $crossfade_pos / 4
    
    	{Use this position to set channel A/B volumes from values in %crossfade_db array}
    	$db_a := %crossfade_db[$crossfade_pos]
    	$db_b := %crossfade_db[16 - $crossfade_pos]
    
    	{Don't pass the current note event on to Kontakt's audio engine}
    	ignore_event($EVENT_ID)
    
    	{Instead, play a note at the appropriate volume with channel A's sample group}
    	disallow_group($ALL_GROUPS)
    	allow_group($group_idx_a)
    	$note_id_a := play_note($EVENT_NOTE, $EVENT_VELOCITY, 0, -1)
    	change_vol($note_id_a, $db_a, 1)
    
    	{Play a note at the appropriate volume on channel B's sample group}
    	disallow_group($ALL_GROUPS)
    	allow_group($group_idx_b)
    	$note_id_b := play_note($EVENT_NOTE, $EVENT_VELOCITY, 0, -1)
    	change_vol($note_id_b, $db_b, 1)
    
    end on
     
Thread Status:
Not open for further replies.