1. Bringing more to our online community - our forum is moving soon!
    We're excited to share more about our plans and information about the future of our online community
    Check our latest update in this thread
    Dismiss Notice

Forcing sample start/end to follow loop start/end

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

  1. Reid115

    Reid115 New Member

    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

    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

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

    Reid115 New Member

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

    on init
        set_listener($NI_SIGNAL_TIMER_MS, 200000)
        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_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 (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.