Scripted Lag

Discussion in 'Scripting Workshop' started by Lovechld2000, May 18, 2019.

  1. Lovechld2000

    Lovechld2000 NI Product Owner

    Messages:
    234
    Kontakt's internal lag feature is cool for dealing with zipper noise from midi sources so I thought I'd script one. This is based on NI's glide code.
    Any ideas how to make this better or am I doing it inefficiently? It can be buttery smooth with a low wait time but that makes the cpu light dance a bit. Full demo below (sublime)
    Code:
    on init
        make_perfview
        set_ui_height_px(50)
    
        declare $lag_bite
        declare $runningtotal := 0
        declare $desiredtotal
    
        declare ui_knob input (0,10,1)
        declare ui_knob $lag_speed(1,1000,1)
        declare ui_knob $output_display(0,1000000,1)
        
    end on
    
    
    function update_cutoff
        $output_display := runningtotal
        set_engine_par($ENGINE_PAR_CUTOFF, runningtotal, 0, 0, -1)
    end function
    
    
    function Rescaler(controller_input, old_min, old_max, new_min, new_max) -> value_output
        declare local ~in_value := int_to_real(controller_input) / 10000.0
        declare local ~in_min := int_to_real(old_min) / 10000.0
        declare local ~in_max := int_to_real(old_max) / 10000.0
        declare local ~out_min := int_to_real(new_min) / 10000.0
        declare local ~out_max := int_to_real(new_max) / 10000.0
        value_output := real_to_int(((in_value - in_min) * (out_max - out_min) / (in_max - in_min) + out_min) * 10000.0)
    end function
    
    
    
    on ui_control (input)
        desiredtotal := Rescaler(input, 0, 10, 0, 1000000)
        call lagged_controller
    end on
    
    
    function lagged_controller
        
        
        if (runningtotal < desiredtotal)
            $lag_bite := 0
            while (runningtotal < desiredtotal)
    
                $lag_bite :=  $lag_speed
                
                if (runningtotal + $lag_bite > desiredtotal)
                    $lag_bite := desiredtotal - runningtotal
                end if
                
                runningtotal := runningtotal + $lag_bite
                
                call update_cutoff
                wait(5000)
            end while
    
        else
    
            $lag_bite := 0
            while (runningtotal > desiredtotal)
    
                    $lag_bite :=  $lag_speed
                
                if (runningtotal + $lag_bite < desiredtotal)
                    $lag_bite := desiredtotal + runningtotal
                end if
                
                runningtotal := runningtotal - $lag_bite
                
                call update_cutoff
                wait(5000)
            end while   
        end if
        
    end function
     
  2. EvilDragon

    EvilDragon Moderator Moderator

    Messages:
    14,589
    Not much you can do there I don't think, as long as you're using KSP it's going to be less efficient than the built-in lag that's on modulators.
     
  3. Lovechld2000

    Lovechld2000 NI Product Owner

    Messages:
    234
    ok thanks for looking at it.
     
  4. medusa

    medusa NI Product Owner

    Messages:
    90
    Here's a similar one that the legendary Big Bob wrote for me many years ago. At the time I specifically wanted to smooth a pitch knob:

    Code:
    on init
      message("")
      declare const scale := 2000
      declare const scale2 := scale/2
      declare const FC := 1000  { filter clcok period, 1 ms }
    
      declare ui_slider Pitch (0,1000000)
      declare ui_slider Watch (0, 1000000)
      declare ui_knob Lag(1,1000, 1)  { time constant TC = 1ms to 1000 ms }
        set_knob_unit(Lag,KNOB_UNIT_MS)
        set_text(Lag,'   Lag')
    
      declare active   { filter clock active }
      declare SOutput  { scaled output }
      declare SPitch   { scaled input }
      declare Output   { filtered input }
          Output := Pitch     { assume equilibrium at start up }
          SOutput := scale*Pitch
          make_persistent(Lag)
          make_persistent(Pitch)
    
          
    end on
    
    on ui_control (Pitch)
      SPitch := scale*Pitch
      if active = 0
        active := 1
        while (abs(SPitch - SOutput) >= scale2)   { while scaled error is larger than scale/2... }
          SOutput := SOutput + (SPitch - SOutput)/Lag    { reduce error by SErr/Lag }
          Output := (SOutput+scale2)/scale
          set_engine_par($ENGINE_PAR_TUNE, Output, -1, -1, -1)
          Watch := Output
          wait(FC)
        end while
        SOutput := SPitch
        active := 0
      end if
    end on
     
  5. Lovechld2000

    Lovechld2000 NI Product Owner

    Messages:
    234
    ah, this is superior to mine. i encountered a divide by zero problem that is solved here and i like the scaled behaviour as it gets nearer the target. supreme
     
    Last edited: May 18, 2019