How to force a formatter function w/o a value change?

I really need some reliable way to cause a formatter function associated with a control to execute and update the display without changing the value.

The reason is that I have presets that have a Master control that scales 2 or more child controls. However, the hardware does not actually change/store the child values - it applies the scaling in real time as needed.

To mimic that, when the preset Master control is changed, I want to have the child controls refresh their display by taking the current value and applying the scaling factor set by the Master.

I got it working somewhat by doing a message:setValue(currentValue) but today it seems to be not working at all. I also tried doing a full setRange() with no success. Simply directly invoking the formatter: fmt34(valueObject, value) doesn’t help.
I also tried the control:repaint(), but that also does nothing.

I’ve tried variations on 3.5, 3.54, and 3.6.0b

So right now I’m confused with no obvious approach

1 Like

I have similar issues when for instance the range of patch numbers should reflect the chosen patch bank. F.i. In the first bank, numbers should range from 0-127, but when changing bank it should show numbers 128-255 on my Roland synth.
I resolve it by using parameterMap get and set commands, where I change the value to one higher and immediately set it back one lower. This does the trick of retriggering the format function.

So it’s not actually without a value change, as you requested.
But in my case nothing is sent by these 2 changes (it is a virtual parameter, so you can control whether it should send something or not) so this does not do any harm.

Yes, that’s how I’ve done it before, but it involves the extra step of adding code to onChange() to prevent sending the up/down value when generated internally versus via incoming sysex or the encoders.

2 Likes

I was wondering about a situation when you needed to call formatter if value stays the same. Now, I get it. I suggest to trigger formatter when any of the “range” attributes is modified? Would that work for you?

Martin - I will give that a try, So - min, max, default. If I set default that should work since the formatter will be displaying information based on the current “value” parameter which is not the same as the default.

I will be home later today and give it a try after I fix the fence in the yard (our dog got out last night and I had to chase it down at 10pm in the evening. lol crazy time.

1 Like

In the example below, assume a change of value in bankSelect from 9 to 10. This forces to move from a bank 9 where the range was 1-128 into a bank 10 with a range that runs 129-255. In the 9th bank, MIDI range = 0-127. In the 10th bank, MIDI range = 0-126 !

When working with ctrlValue:setRange this doesn’t refresh the parameter value from parameter 12033 (corresponds with control #4) from let’s say 20 into 147. Instead control 4 shows 128.

function bankSelect(valueObject, value)
 value = value + 1
local bankGroup = { -- MSB, LSB and ranges for my XV5080 banks
  {87,64,128},{87,65,128},{87,66,128},{87,67,128},{87,68,128},{87,69,128},{87,70,128},{1,0,128}, -- preset A-G + GM
  {89,6,128},{89,7,255},{89,10,128},{89,11,255},{89,14,128},{89,15,255},{89,18,128} -- SR-JV 4, 6, 8, 10
   }
  midi.sendControlChange (devPort, channel, 0, bankGroup[value][1])
  midi.sendControlChange (devPort, channel, 32, bankGroup[value][2])
  local control = controls.get (4) -- patch number
  local valueObjects = control:getValues ()
  local ctrlValue = control:getValue ("")
  local message = ctrlValue:getMessage ()
  if bankGroup[value][3] > 128 then
    message:setMax (bankGroup[value][3]-129) -- set max MIDI value
    ctrlValue:setRange (129, bankGroup[value][3], 0, false)
  else
    message:setMax (bankGroup[value][3]-1) -- set max MIDI value
    ctrlValue:setRange (1, bankGroup[value][3], 0, false)
  end
end

The old trick works: this changes a shown value 20 of control 4 (or parameter 12033) into a refreshed value of 147 when bankGroup changes from 9 to 10

function bankSelect(valueObject, value)
  value = value + 1
local bankGroup = { -- MSB, LSB and ranges for my XV5080 banks
  {87,64,128},{87,65,128},{87,66,128},{87,67,128},{87,68,128},{87,69,128},{87,70,128},{1,0,128}, -- preset A-G + GM
  {89,6,128},{89,7,255},{89,10,128},{89,11,255},{89,14,128},{89,15,255},{89,18,128} -- SR-JV 4, 6, 8, 10
   }
  midi.sendControlChange (devPort, channel, 0, bankGroup[value][1])
  midi.sendControlChange (devPort, channel, 32, bankGroup[value][2])
  local control = controls.get (4) -- patch number
  local valueObjects = control:getValues ()
  local ctrlValue = control:getValue ("")
  local message = ctrlValue:getMessage ()
    ctrlValue:setRange (0, bankGroup[value][3], 0, true) -- set both display and MIDI min max
  if bankGroup[value][3] > 128 then
    ctrlValue:setMin (129) 
    message:setMax (bankGroup[value][3]-129) -- set max MIDI value
  else
    ctrlValue:setMin (1) -- set min display value
    message:setMax (bankGroup[value][3]-1) -- set max MIDI value
  end
  parameterMap.set (deviceId, PT_VIRTUAL, 12033,parameterMap.get (deviceId, PT_VIRTUAL, 12033)+1) -- refresh the shown value
  parameterMap.set (deviceId, PT_VIRTUAL, 12033,parameterMap.get (deviceId, PT_VIRTUAL, 12033)-1)

The formatter is now called (as of firmware v3.6.0) whenever a message or value range is changed. Additionally, changing a default value also triggers the formatter.

1 Like

That works fine now.
Another most subtle challenge:
on the Korg Kingkorg there are 3 banks, each with 100 patches. There is A001-A100, B001-B100 and C001-C100.
I choose the patch using a list control “Bank Select” to set the bank (value 0, 1 or 2 for A, B or C) and a fader control to choose the program number (1-100). Cfr screenshot.

But I like to show the bank number A, B or C as part of the patch number as the format for the list control, and do so with a formatter function called “displayPatch”

When I change “Prog Number”, the formatting works fine. But it would be great that I could invoke the formatter for that Prog number fader also when changing the Bank.

Take a look in the bottom right corner of this test preset

I use the set default in the bank control to change the display in the patch.
Take a look at the formatter and function for the bank and patch controls.

Thanks @oldgearguy

I see you use getValue and setDefault. Haven’t done that before.

   valObj = controls.get(3):getValue("value")
   valObj:setDefault(cVal)

So getValue is meant to fetch the right object referring to the value property of control 3?
And then setDefault is a function setting that value to cVal? And by doing so, you retrigger the formatting of that control?

I’ve already applied it in my KingKorg preset. Code is less dirty now :slight_smile:
Every day is a good day to learn :smiley:

Ignace

Yes, right on both counts. @martin 's tweaks to how some of the built-in functions work make it easier for this kind of cross-control behavior.

I have a lot of presets that could use a refresh now that I know more and with all the OS updates that have happened.

1 Like

(post deleted by author)

Hello, got your message. I’ll look at it in more detail later this morning.

I might do things like this in some of my presets.

Tom

Hi Tom,
no worries. I’ve changed my mind and will actually use the control value as set by the formatting function based on the parameter value, and simultaneously use the name to show the current derived value from the other controls. By using a thin fader, both values will be separated by the line in between.