[Solved] MIDI IN: How to reach the value in the knobs without jumping?

This is a bit advanced. I am trying to improve the behavior of a 270º turn knob (physical), to avoid the jump that can occur from a knob or fader when the user changes a value from Renoise and then it is controlled from the physical knob or fader of a MIDI keyboard or controller.

A concrete case is the following one:

vb:valuebox {
  id = "PHT_VB_SEL_TRK_1",
  height = 25,
  width = 54,
  min = 0,
  max = 999,
  value = 0,
  tostring = function( number ) return pht_tostring_track_1( number ) end,
  tonumber = function( string ) return pht_tonumber_track_1( string ) end,
  notifier = function( value ) pht_sel_trk_1() pht_anchor_track_1( value ) end,
  midi_mapping = "Tools:PhraseTouch:Panel_1:Track & Instrument:Track Selector Valuebox",
  tooltip = "Choose a track number\n[SEL = default selected track]"
}

This valuebox shows the value of the selected track (is an example of many). The user can change the value in 3 ways:

  1. From the valuebox with the mouse.
  2. From the MIDI in linked with this valuebox.
  3. From Renoise by changing the track selection (keyboard commands, mouse).

The MIDI input is defined with its midi_mappingand the nextrenoise.tool():add_midi_mapping { } :

---
renoise.tool():add_midi_mapping {
  name = "Tools:PhraseTouch:Panel_1:Track & Instrument:Track Selector Valuebox",
  invoke = function( message )
    if message:is_abs_value() then
      local val = math.floor( message.int_value * ( vws.PHT_VB_SEL_TRK_1.max + 1 )/128 )
      if ( val <= 128 ) then
        vws.PHT_VB_SEL_TRK_1.value = val
      else
        return
      end
    end
  end
}

The matter is here, within the condition: if message:is_abs_value() then bla, bla bla, end

By turning the knob, you will always be synchronized with the valuebox. The local val is shielded in case the maximum number of tracks changes.So, the 128 values of message.int_value always adjust to the maximum number of tracks in each execution.

But there is a very specific case, which is when the user selects a track from Renoise. The knob is not motorized, it remains fixed in place, just like the valuebox, but the value of the selected track has changed. Then, if the user uses the knob, there will be a sudden jump in the selection and this is exactly what I want to avoid, at least from the knob (or fader).

Does anyone think of how to solve this?

vws.PHT_VB_SEL_TRK_1.value = val is the one that updates the selection of the track.In theory, changing this line would be possible.I have tried the following, but it seems incoherent, and it does not work:

if ( vws.PHT_VB_SEL_TRK_1.value == val ) then
  vws.PHT_VB_SEL_TRK_1.value = val
end

What I thought was: do not change the value of the valuebox until the value of the knob is the same.But this does not work like that, it’s just the other way around:

if ( vws.PHT_VB_SEL_TRK_1.value ~= val ) then
  vws.PHT_VB_SEL_TRK_1.value = val
end

That is the same as not putting the condition. It is the same as this:

vws.PHT_VB_SEL_TRK_1.value = val

It needs to be unequal, so you can change the value.So, how to force the knob to do nothing, until it reaches the value of the current selection?The objective is to avoid the jumps that occur in the knobs or faders.

This issue can be useful in many cases…

Can someone help me here?

The Duplex mixer supports both motorized and non-motorized faders, so it has to deal with a similar situation.

In order to avoid those sudden jumps, the mixer basically memorizes the most recent changes to the fader values from the hardware and then checks incoming values - potentially ignoring the input.

The concept is also known as “soft takeover”, you might get some ideas by googling that term?

The Duplex mixer supports both motorized and non-motorized faders, so it has to deal with a similar situation.

In order to avoid those sudden jumps, the mixer basically memorizes the most recent changes to the fader values from the hardware and then checks incoming values - potentially ignoring the input.

The concept is also known as “soft takeover”, you might get some ideas by googling that term?

Thanks!Ok, I’ll take a look at the term "soft takeover"to see if I find any solution. I did not know what it was called like that.At the moment, I have not seen anything related to LUA.I just read this:

https://www.native-instruments.com/forum/threads/soft-takeover.156304/

It seems that this theme is in many programs with MIDI Input.Anyway, I do not think I’ll find any similar example in LUA to solve it.

In order to avoid those sudden jumps, the mixer basically memorizes the most recent changes to the fader values from the hardware and then checks incoming values - potentially ignoring the input.

I think I have an idea to do this.But I will have to do trial and error tests :slight_smile:

In order to avoid those sudden jumps, the mixer basically memorizes the most recent changes to the fader values from the hardware and then checks incoming values - potentially ignoring the input.

Solved!!!

I have 2 different cases to apply the"soft takeover" and I have solved them both in a similar way to the following:

local pht_vol_sld_pos_1 = 0

renoise.tool():add_midi_mapping {
  name = "Tools:PhraseTouch:Panel_1:Volume:Note Volume Slider",
  invoke = function( message )
    if message:is_abs_value() then
      local val = message.int_value
      if ( pht_vol_sld_pos_1 == math.floor( vws.PHT_SLIDER_VOL_1.value ) ) then
        vws.PHT_SLIDER_VOL_1.value = val
      end
      pht_vol_sld_pos_1 = val --soft takeover
    end
  end
}

This is a slider, with a range of 0 to 127 with your midi_mapping. So it does not include any mathematical adjustment operation. However, vws.PHT_SLIDER_VOL_1.value returns decimalsand I had to add math.floor() to make it work.Finally, the local pht_vol_sld_pos_1 stores the value to match, and thus avoid the jumps.You just have to wrap it with one condition and that’s it.


The following is another case with more convoluted things, but that includes the same method, with its location and condition.

local pht_sel_ins_pos_1 = 0
function pht_sel_ins_1()
  vws.PHT_VB_SEL_INS_1.max = #song().instruments
  local sii = song().selected_instrument_index
  local val = vws.PHT_VB_SEL_INS_1.value
  local ins_1
  if ( val == 0 ) then
    ins_1 = sii
  else
    if ( val > #song().instruments ) then
      ins_1 = sii
      if ( val ~= sii ) then
        vws.PHT_VB_SEL_INS_1.value = sii
      end
    else
      ins_1 = val
      if ( PHT_ANCHOR_1 == true ) then
        if ( pht_sel_ins_pos_1 == song().selected_instrument_index ) then
          song().selected_instrument_index = val
        end
        pht_sel_ins_pos_1 = val --soft takeover
      end
    end
  end
  return ins_1
end

The result is magnificent. This is easier to control from the MIDI hardware.

I only have one question about the unlimited spin knobs.How do they work? Is it necessary to write specific functions for them compared to the 270º rotation knobs?Unfortunately, I do not have any MIDI keyboard that has unlimited spin wheels to test it.

I only have one question about the unlimited spin knobs.How do they work?

Relative (endless) encoders are not emitting “special” MIDI messages as such, it depends on how you interpret the messages.

Luckily, Renoise takes care of auto-detecting how the controller is outputting values, and translates it into a simple numeric value for you.

So, to use a relative value in your tool you need to keep track of the value yourself, and increase/decrease this value by the amount that you receive from the hardware.

Relative (endless) encoders are not emitting “special” MIDI messages as such, it depends on how you interpret the messages.

Luckily, Renoise takes care of auto-detecting how the controller is outputting values, and translates it into a simple numeric value for you.

So, to use a relative value in your tool you need to keep track of the value yourself, and increase/decrease this value by the amount that you receive from the hardware.

So, in this case it is like having two buttons, right and left, and adding or subtracting a unit or value as appropriate.These wheels routed with MIDI Input would be ideal for changing the presets for the VSTi.I guess until I have a MIDI keyboard with these infinite spin wheels, I will not be able to program it.

Thanks for all the help! I declare this thread as resolved.