Map a range of (MIDI controller) values to an action

Hi all

Bit new to this so go easy on me!

I wish to map a range of MIDI controller values to a single key command, so for example
''When MIDI controller 10 value is greater than 0 but less than 10, perform the following action.''

I have the following so far (see attached) but don't see a 'changes to <value<' option.

Is it as simple as unticking 'Triggered by any of the following'?

TIA

Hi and welcome to the forum!

I'm curious to know the application of this, but in the meantime here's an idea for you to try...

This method requires two macros: One that sets the incoming CC value to a global variable, and another that determines which of a number of ranges that value falls into before performing actions accordingly.

If you wish to change from divisions of 10 to something else, simply alter the Max CC Value Table and then change the Switch/Case conditions to reflect it.

Midi Range - Detect.kmmacros (41 KB)

Macro screenshot

Midi Range - Actions.kmmacros (46 KB)

Macro screenshot

Hey thanks for the swift reply - much appreciated

I have to say that as a relative noob with KBM I have no clue what your first macro means, how it works or how to recreate it, but appreciate your suggestion all the same. And I thought it was a relatively simple ask!!

Here's what I'm up to in case useful - I have created a graphic prototype in Figma to represent a MIDI sweep type foot controller, with 16 LED segments each with a key command attached to trigger it. As Figma doesn't yet read MIDI the incoming MIDI from the actual footpedal needs translating to key commands, and as you know a MIDI CC as sent by such a pedal has 128 different values so CC values need to be grouped into 16 sets, each one assigned to its own key command. Hope that makes sense!

Firstly, I updated the macros above to make the second one do most of the work.

As you can see, it's set to trigger any time the value of that CC changes. When it does, KM makes a note of the incoming CC value. A typical MIDI trigger value looks like this:

1,1,95,MPKmini2 (channel, cc, value, device)

We want the value, so we access that by setting a variable to %TriggerValue[3]%. (For more information about the TriggerValue token, read THIS.)

The second macro sets a variable to a set of range maximums. It then loops through each of these and sets another variable (MidiCCRange) to that number IF it's larger than the incoming CC value. I realise this might be hard to visualise.

Imagine the incoming CC value has set our global variable (InputMidi) to 43. The second macro loops through the table like this:

10 - yep, the CC value is bigger than this, so set MidiCCRange to 10
20 - yep, the CC value is bigger than this, so set MidiCCRange to 20
30 - yep, the CC value is bigger than this, so set MidiCCRange to 30
40 - yep, the CC value is bigger than this, so set MidiCCRange to 40
50 - nope, the CC value isn't bigger than this, so do nothing

We can now use the number 40 to determine which action will be performed in the Switch/Case group.

You don't need to. Download the two macros above and use them. All you need to do is click MIDI Learn at the top of the first macro and wiggle the control you want to use, then put some actions in the second macro and assign it a hotkey.

In that case, change Max CC Value Table to this:

7
15
23
31
39
47
55
63
71
79
87
95
103
111
119
127

...and adjust the second macro's Switch/Case entries to match.

Just be aware that if you want to use KM to do this, you may experience a bit of a resource overhead when rapidly moving the control as KM will be triggered many times per second. I don't know what Figma is, and I'm sure you've done your research, but you should be sure it doesn't support MIDI before going the KM route.

Here are a couple of links in case they're relevant.

Link 1
Link 2

Thanks for the replies - very useful. And good to know about the resource overhead as that is obviously key to smooth operation. I will run a few tests.
Much appreciated

You'll hate me, @noisneil -- but it's maths time! :wink:

If your numbers are in regular chunks like this, then number DIV chunksize is the "chunk number", where the first "chunk number" is 0 -- using your example above:

when CC=3, (3 DIV 10) = 0
when CC=13, (13 DIV 10) = 1
when CC=23, (23 DIV 10) = 2
when CC=33, (33 DIV 10) = 3
when CC=43, (43 DIV 10) = 4

And if you want "the biggest multiple of chunkSize that's less than or equal to CC" you can generalise to:

(Local_CC DIV Local_chunkSize) * Local_chunkSize

It's slightly different when, as in @thirdspace's numbers, you're starting from 0 rather than 1. You can do

((Local_CC +1) DIV Local_chunkSize) * Local_chunkSize - 1

if you're happy that 0-6 map to -1.

Only if you keep calling me a DIV. :joy:

So does DIV divide a number and round it to the nearest integer?

With your idea, we don't need a table at all and the entire second macro can be reduced to a single action and a Switch/Case!

Midi Range - Actions.kmmacros (44 KB)

Macro screenshot

I suppose my first offering might still be useful if, for some reason you wanted uneven range sizes... With a rotary controller, I could imagine a few scenarios where you might want different rates of change in the centre of the range-of-motion to those at the extremes.

InputMidi DIV 8 works great, so I don't know what the problem is you're solving with the above.

@thirdspace The macros I've provided work as follows:

  • Move a MIDI control.
  • Trigger the second macro.
  • Actions triggered by the second macro are determined by the current CC value.

Based on this, I thought that was what you were looking for. Is that right?

Since you described the sweeping LEDs, I wonder if what you actually want is a single macro that does something when the CC Value enters each range. Is that the case?

1 Like

Having listened to Iron Maiden all afternoon -- I'd rather be a DIV than a MOD any day :wink:

No rounding. It's "integer division, ignore the remainder". Subtle difference, but both numbers are treated as integers and the result is an integer -- no floats involved.

Now, you're getting it -- for regular "chunks" you can use DIV in the Switch and the inner result in the Cases. If you have either a known set of possible results or can get away with a "default" case for "all the cases we haven't written down".

My bad, misread the range divisions and thought the numbers were the bottom of each range rather than the top (I read it as 0-6, 7-14... instead of 0-7, 8-15...) A brain-fart -- it's been a long day...

That aside... Loops are great, but for something regular and defined you can usually use maths rather than testing every number in turn. And while it looks scary when written down, we do it every day -- without even thinking about it. Something's going to take 80 minutes? That's in 80 DIV 60 hours and 80 MOD 60 minutes time...

Having never played with these triggers -- can you include a calculation in them? There's obviously knowledge of previous and current state -- there's increases and decreases -- but can you do changes > Global_previousRange + 8?

1 Like

I'm not at my machine at the moment but I don't think so. Let's hold off on that avenue until @thirdspace confirms the use-case.

Good question - each LED on the graphic should light when the CC value enters the relevant range; however the incoming MIDI CC value will always start in the middle of a range and the other values in that range should be recognised before the CC value crosses a boundary into an adjacent range if that makes sense?

yes - just thinking about this. The scenario might look like this: a graphic with 16 led segments each of which is mapped to a CC value range. This is the virtual representation of a single physical MIDI footpedal. The graphic however will be replicated for each 'patch'. In my head the CC value ranges will be the same from patch to patch, but the CC number will change. (Patch 1, CC1; Patch 2 CC2, etc). When switching the graphic from patch to patch it should 'recall' the state it was left in before changing patch, without having to send further CC values (i.e. moving the footpedal). Now, this might not be the scenario you are thinking of here but I just thought I would drop this in.
Input much appreciated btw

CC Value ranges are:
0
1-8
9-16
17-24
25-32
33-40
41-48
49-56
57-64
65-72
73-80
81-88
89-96
97-104
105-112
113-120
121-127

So 17 'ranges' to map to the 16 virtual LEDs and one for the 0 (off) state

For info Figma is a graphic UI prototyping tool - unfortunately doesn't support MIDI as a trigger (yet)

Hmm. This might complicate things slightly. Unless I'm mistaken (and I'm fairly sure @Nige_S will tell me if I am), we might have to revert to my looping method with a bespoke value table.

So how are you triggering the LED graphics? Keyboard shortcuts? One per state?

Give this a try. It's not using quite the values you posted earlier; it's using DIV 8 and then reserving the value of 0 to turn the LEDs off, so the first "batch" has one value missing. I don't think it will make any real-world impact on the function of the macro, but @Nige_S will probably be able to improve on this, knowing him...

Midi Range Trigger.kmmacros (49 KB)

Macro screenshot

Nah, it's just an offset -- (Local_ccValue + 7) DIV 8 (we don't care that 127+7=134 is outside our CC value range coz it still DIVs into our "chunk range").

Quick tester so you can see values map to ranges properly:
CC Test.kmmacros (4.7 KB)

@thirdspace -- depending on what you're doing next you may not need "Switch/Case", you might be able to use the "range number" directly eg as the number of lights to turn on, a signal multiplier, scaling a graphic, etc.

1 Like

What am I looking at here?

CleanShot 2022-07-07 at 19.02.05

CC value of 35 would map to the 5th CC value range in @thirdspace's table (33-40), 77 maps to the 10th (73-80), 57 to the 8th (57-64). It's just a simple sanity check, looks like we're returning the right numbers, so we're good to use it in production.

Reckon you might be able to transplant that into this?

It's ready for it -- just need to hear if @thirdspace needs the long list of Case statements or simply do something directly using the number returned.