Forcing sample start/end to follow loop start/end

Discussion in 'Scripting Workshop' started by Reid115, Jul 31, 2021.

  1. Reid115

    Reid115 New Member

    Messages:
    3
    So basically in kontakt's wave editor, you have the start/end markers, and you have loop regions. What I want is for the start/end markers to automatically move to the start/end bounds of the currently selected loop region whenever I move/scale it. This would make it very easy to quickly scrub the loop region around and find loops that sound good (without having to readjust the markers every single time). I don't want to hear the content outside the loop region. Seems like a very simple function, but surprisingly it's not looking like there's any way to do this. You would think the loop mode dropdown would have a mode where the sample just jumps straight to the loop region to begin with. I'm trying to write a KSP script that does this. I tried to set $ZONE_PAR_SAMPLE_START and $ZONE_PAR_SAMPLE_END based on $LOOP_PAR_START and $LOOP_PAR_LENGTH, but learned that set_zone_par() only works on "user zones". So I made a user zone with a DnD'ed sample, but it seems like this removes all user functionality in the wave editor, defeating the whole purpose. Any help? Thanks.
     
  2. EvilDragon

    EvilDragon Moderator Moderator

    Messages:
    19,474
    There is no function in Kontakt that does what you want, indeed. You would need to script your own loop start/end handles going over a ui_waveform display to do what you want.
     
  3. Reid115

    Reid115 New Member

    Messages:
    3
    Dang, okay. I'll see if I can pull off your suggestion. Thanks for the quick reply.
     
  4. Reid115

    Reid115 New Member

    Messages:
    3
    So I made some progress but I'm stuck on a few things. Here's my (WIP) code:

    Code:
    on init
        message("")
        set_listener($NI_SIGNAL_TIMER_MS, 200000)
        set_ui_height_px(50)
    
        declare ui_mouse_area $dnd
        set_control_par(get_ui_id($dnd), $CONTROL_PAR_DND_ACCEPT_AUDIO, $NI_DND_ACCEPT_ONE)
        set_control_par(get_ui_id($dnd), $CONTROL_PAR_DND_ACCEPT_ARRAY, $NI_DND_ACCEPT_ONE)
        set_control_par(get_ui_id($dnd), $CONTROL_PAR_RECEIVE_DRAG_EVENTS, 1)
    
        set_num_user_zones(1)
        set_zone_par(%NI_USER_ZONE_IDS[0], $ZONE_PAR_LOW_KEY, 0)
        set_zone_par(%NI_USER_ZONE_IDS[0], $ZONE_PAR_HIGH_KEY, 127)
        set_zone_par(%NI_USER_ZONE_IDS[0], $ZONE_PAR_LOW_VELO, 0)
        set_zone_par(%NI_USER_ZONE_IDS[0], $ZONE_PAR_HIGH_VELO, 127)
        set_zone_par(%NI_USER_ZONE_IDS[0], $ZONE_PAR_ROOT_KEY, 60)
    
        set_loop_par(%NI_USER_ZONE_IDS[0], 0, $LOOP_PAR_MODE, 1)
        set_zone_par(%NI_USER_ZONE_IDS[0], $ZONE_PAR_SAMPLE_MOD_RANGE, 0)
        declare $start := 0
        declare $length := 20000
    
        move_control_px($dnd, 70, 2)
        set_control_par(get_ui_id($dnd),$CONTROL_PAR_WIDTH, 78)
        set_control_par(get_ui_id($dnd),$CONTROL_PAR_HEIGHT, 39)
       
        {declare ui_label $dnd_label (2, 2)
        set_text($dnd_label, "Drag sample here!")
        move_control_px($dnd_label, 78, 10)
        set_control_par(get_ui_id($dnd_label),$CONTROL_PAR_WIDTH, 70)
        set_control_par(get_ui_id($dnd_label),$CONTROL_PAR_HEIGHT, 40)}
       
        declare ui_waveform $dnd_wf (2, 2)
        attach_zone($dnd_wf, %NI_USER_ZONE_IDS[0], 0)
        set_control_par(get_ui_id($dnd_wf), $CONTROL_PAR_BG_COLOR, 91e1e1eh)
        set_control_par(get_ui_id($dnd_wf), $CONTROL_PAR_WAVE_COLOR, 9ffffffh)
        move_control_px($dnd_wf, 70, 2)
        set_control_par(get_ui_id($dnd_wf),$CONTROL_PAR_WIDTH, 78)
        set_control_par(get_ui_id($dnd_wf),$CONTROL_PAR_HEIGHT, 39)
    
        declare ui_knob $start_knob (0, 1000, 10)
        move_control($start_knob, 2, 1)
        set_text($start_knob, "Start")
        set_knob_defval($start_knob, 0)
        set_knob_unit($start_knob, $KNOB_UNIT_PERCENT)
    
        declare ui_knob $length_knob (0, 4000, 1)
        move_control($length_knob, 3, 1)
        set_text($length_knob, "Length")
        set_knob_defval($length_knob, 1000)
        set_knob_unit($length_knob, $KNOB_UNIT_MS)
    
        declare ui_switch $grid
        move_control_px($grid, 340, 23)
        set_text($grid, "Grid")
        set_control_par(get_ui_id($grid),$CONTROL_PAR_WIDTH, 31)
    
        declare ui_knob $fade_knob (0, 1000, 10)
        move_control($fade_knob, 5, 1)
        set_text($fade_knob, "X-Fade")
        set_knob_defval($fade_knob, 100)
        set_knob_unit($fade_knob, $KNOB_UNIT_MS)
    
        declare ui_switch $freerun
        move_control_px($freerun, 538, 12)
        set_text($freerun, "Freerun")
        set_control_par(get_ui_id($freerun),$CONTROL_PAR_WIDTH, 56)
    end on
    
    on listener
        $start := $start_knob * 1000000 / 1000
        $length := $length_knob * 100000 / 1000
        {wait_async(set_loop_par(%NI_USER_ZONE_IDS[0], 0, $LOOP_PAR_START, $start))
        wait_async(set_loop_par(%NI_USER_ZONE_IDS[0], 0, $LOOP_PAR_LENGTH, $length))
        wait_async(set_zone_par(%NI_USER_ZONE_IDS[0], $ZONE_PAR_SAMPLE_START, $start))
        wait_async(set_zone_par(%NI_USER_ZONE_IDS[0], $ZONE_PAR_SAMPLE_END, $start + $length))}
        wait_async(set_zone_par(%NI_USER_ZONE_IDS[0], $LOOP_PAR_XFADE, $fade_knob))
    end on
    
    on ui_control ($dnd)
        if ($NI_MOUSE_EVENT_TYPE = $NI_MOUSE_EVENT_TYPE_DROP)
            if (num_elements(!NI_DND_ITEMS_AUDIO) = 1)
                wait_async(set_sample(%NI_USER_ZONE_IDS[0], !NI_DND_ITEMS_AUDIO[0]))
                {set_text($dnd_label, get_sample(%NI_USER_ZONE_IDS[0], $NI_FILE_NAME) & "." & get_sample(%NI_USER_ZONE_IDS[0], $NI_FILE_EXTENSION))}
            end if
        end if
    end on
    
    The 4 commented out lines in the listener are the biggest issue for me. If I uncomment them, the audio when I press down a key immediately glitches out. I originally had those lines in dedicated ui_control callbacks for the $start_knob and $length_knob, and the audio sounded fine, but the knobs would move really slowly. Even with the listener, I have to put the timer at 100000+ microseconds for the knob function to not lag the visual refresh. This doesn't seem right to me; I guess I don't really understand how the listener/threading works. If you run the code, have the wave editor open to view what's going on.

    Two other misc. questions:
    1. get_sample_length() returns microseconds but $ZONE_PAR_SAMPLE_START takes samples. Is there a way to convert? I'm currently using 44100 but I don't like the idea of just hardcoding that number in when the sample rate could technically be different.
    2. Is there a way to draw the loop start/end markers over ui_waveform? I don't need them to be clickable; I just want the visualization. The manual only seems to discuss the waveform colors and the playback cursor.

    Any help is appreciated.