Change play position in the middle of a note (custom looping)

Reid115
Reid115 Member Posts: 47 Member

I'm implementing a custom looping mechanic where the user can drag start/end loop cursors over a waveform. Changing the engine's loop points with the following code is kind of slow, so calling it every time the user drags one of the cursors causes the cursors to move very slowly:

wait_async(set_loop_par(%NI_USER_ZONE_IDS[0], 0, $LOOP_PAR_START, $left))
wait_async(set_loop_par(%NI_USER_ZONE_IDS[1], 0, $LOOP_PAR_START, $left))
wait_async(set_loop_par(%NI_USER_ZONE_IDS[0], 0, $LOOP_PAR_LENGTH, $right))
wait_async(set_loop_par(%NI_USER_ZONE_IDS[1], 0, $LOOP_PAR_LENGTH, $right))

The other issue is that the $left and $right params need to be sent in samples, not milliseconds, and I don't see any way to get samples without knowing the sample rate. So anyways, I'm trying to do the looping manually from the script. In my listener, I'm doing this:

if (get_event_par($l_id, $EVENT_PAR_PLAY_POS) >= $right_ms)
    set_event_par($l_id, $EVENT_PAR_PLAY_POS, $left_ms)
end if

...but I realized you can't use set_event_par() on $EVENT_PAR_PLAY_POS, only get_event_par(). Is there any workaround for this? I don't want to trigger another note. Thanks.

Best Answer

  • EvilDragon
    EvilDragon Moderator Posts: 1,021 mod
    Answer ✓

    $EVENT_PAR_PLAY_POS is indeed only a getter, not a setter. You cannot change these things without playing another note, unless you are in sampler mode and use internal modulation to modulate the loop start and loop length. And that is done in % only.

Answers

  • EvilDragon
    EvilDragon Moderator Posts: 1,021 mod
    Answer ✓

    $EVENT_PAR_PLAY_POS is indeed only a getter, not a setter. You cannot change these things without playing another note, unless you are in sampler mode and use internal modulation to modulate the loop start and loop length. And that is done in % only.

  • Reid115
    Reid115 Member Posts: 47 Member

    Dang, okay. I managed to work out a sneaky solution with the engine loop. When a new sample is loaded, I do this:

    wait_async(set_loop_par(%NI_USER_ZONE_IDS[0], 0, $LOOP_PAR_START, 0))
    wait_async(set_loop_par(%NI_USER_ZONE_IDS[0], 0, $LOOP_PAR_LENGTH, 2147483647))
    $samples := get_loop_par(%NI_USER_ZONE_IDS[0], 0, $LOOP_PAR_LENGTH)
    

    Sending the max integer to the loop length will automatically shorten the length to the full sample, from which I can retrieve the sample length in samples. Then I set the loop bounds like so ($left and $right are slider values from 0-1.4bil):

    wait_async(set_loop_par(%NI_USER_ZONE_IDS[0], 0, $LOOP_PAR_START, real_to_int(int_to_real($samples) * int_to_real($left) / 1400000000.0)))
    wait_async(set_loop_par(%NI_USER_ZONE_IDS[0], 0, $LOOP_PAR_LENGTH, real_to_int(int_to_real($samples) * int_to_real($right - $left) / 1400000000.0)))
    

    As far as my loop cursors moving slowly, I just made a "loop adjust" button. When it's on, no events will play, and you can adjust the loop points. When it gets turned back off, only then will the new points be set, so it's not constantly calling those functions as you're moving the cursors.

Back To Top