How do I map a continuous controller in relative mode?


I am test driving GigPerformer as replacement for MainStage. As a start, I am attempting to implement equivalent of what I have in my goto MainStage template. I would like to connect to the same gear without having to program the hardware differently if possible.

Now to my problem.

I can’t find how to set up the control widget map to use rotary encoders that operate in relative mode. Absolute mode is when the rotary encoder has been set up to emulate a pot or a fader (remembering the value of the CC being sent). Relative mode is when it sends a signed value to indicate moving up or down (and magnitude can vary based on speed).

The advantage of relative mode is that the up / down is always relative to the state in the software rather than storing (and sending) values as absolutes from the hardware. This avoids the whole glitch that can happen when you adjust a dial after a rack panel change (and the software syncs to the hardware).

Without the proper mapping the control widget just clamps onto the two extremes based on movement either way (presumably because the signed values emitted per notch of the encoder are usually 1 for clockwise or -1 represented by 127 for counterclockwise) How do I set up the widget for relative mode CCs? (Or maybe there is a script for this?)

Hmm, you’re the first person in three years to ask for relative mode :slight_smile: It’s not built-in right now but it would be very easy to do this with GP Script using a MIDI callback.

However, widgets do have a catch mode so that when you switch to another rackspace, and turn a physical knob, nothing will happen until the value of the physical knob crosses over the current position of the widget in the new rackspace so that avoids the glitch.

GP3 also supports controllers like the MIDI Fighter Twister or the Behringer Xtouch Mini such that when you switch rackspaces, the widgets in the new rackspace send their current positions to the controller so that everything stays synchronized.

There seems to be several different ways to do this — can you tell me exactly what MIDI events your rotary controls are sending? Are they CC numbers (different for each rotary) and a value >= 64 meaning increment and a value < 64 meaning decrement?

Thanks for the reply. The controller is an iRig Keys I/O 25. It sends 7 bit two’s complement which I believe means that it sends a 1 for each increment and 127 (-1) for each decrement. If I spin the control knob fast enough I can see the increment values go greater than 1 and the decrement values go below 127 (126 for -2, etc).

As you turn the knob, it sends the stream of increments or decrements.

The CC #'s of the main 8 knobs (by default) are CC#12…19. The ‘data’ knob is CC#22. (And I suppose changing such to tailor it to various different hardware controllers would be simple).

I think that a script should work for this, as you mentioned. It would be especially great if the script can read the value from the destination’s state, apply the increment / decrement value to it, and then write it back. That way, after a rack change, it would start applying movement towards the new recalled value. When switching back, it would apply to the point that is recalled (based on the behaviour of first time versus going back to the rack space).

So if you turn clockwise slowly it sends a CC value of 1 (and maybe two or three if you go faster) and if you turn anticlockwise, it sends a CC value of 127, etc?

How “fast” does it turn? In other words, if you’re going clockwise, what’s the highest value that it sends out? I assume it can’t be more than 63 but does it go that high?

The real question here is how should widget values increment or decrement as these values come in? Understand that widgets can represent far more steps than MIDI’s 128 discrete values.

A script would do exactly as you describe, get the current widget value (state) and apply the appropriate delta. It’s pretty trivial If we only allow 128 steps, then the delta in “widget world values” would be some multiple of .0078125 (1/128) but we can allow much finer changes than that and it might be that if you’re turning really slowly, we could do finer ranges, that’s why I’m interested in how big those values get.

I’m actually on an airplane coming back from NAMM, but I’ve just created a rackspace with three widgets to test such a mechanism by simulating CC events from another tool.

Here’s the rackspace for you to try out — all you should have to do is change the actual MIDI device in the rackspace so that it corresponds to your iRig. Then the first three widgets should work.

I don’t normally write user scripts but since I don’t have your controller and because I think we should probably add a “relative” mode into our system so that scripting is not necessary, I figure it’s worth building this to test if it will work. Let me know. (3.5 KB)

I haven’t seen it exceed +10 or -10 and that’s turning the knob like a madman.

I never thought of ‘resolution’ per click.

I will give you script a test drive.

Yeah, that’s the thing — there’s no reason our widget changes should be linear — we could do very fine adjustments when you turn slowly, way more fine than is possible with MIDI and then do larger adjustments if you turn a bit faster.

Script works great. I am going to see if this can be extended and integrated into my rack space.

1 Like

Hi everyone,
my MIDI keyboard is a M-Audio Code 61 and the controller knobs on it are also configurable to ‘relative’ mode (which i have tried now).
In my case, the controller values are sent as follows: clockwise = 65 / anticlockwise = 1
(There also are other variations of how to configure the controller values 127/1 or the opposite direction 1/65 or 1/127… but i decided to leave it to 65/1).
There is no acceleration recognized, the values are static, no matter how fast the knob is turned.

@dhj: I tried your script (which i had to modify a little bit) and it worked well with fixed increment values.
But it would be much nicer if the adjustment-values were ‘time-based’:
Like an algorithm that collects the number of incoming signals within a (say) 100ms and then calculates an adequate in-/decrement which is then added to the WidgetValue. So the refresh rate of the widget would be 100ms, which may have to be fine-adjusted… but i think the idea behind it is clear.
Now all i have to do, is to write a script that actually works as intended (my first try hung up GP completely… :woozy_face: but i won’t give up!)

Hi - I started a thread on a similar topic so I hope you don’t mind if I chip in.

I have a Novation SL61 mkii controller and it would be nice to be able to use its endless controllers in relative mode. I think I could do this with some scripts but it might be good to build this in as a feature for a future release.

Unfortunately, it looks like there are a number of protocols used for midi encoders but for the record the SL61 endless controllers (and probably most Novation controllers) can be configured to send out midi messages using one of 4 protocols as follows …

REL1 (Relative 1): A message with value 65 is sent out for every clockwise step (increment) and a message with value 63 is sent out for every anti-clockwise step (decrement). With this option the encoder functions as a true endless control rather than emulates an analogue pot as with the 0-127 and -64/+63 settings.

REL2 (Relative 2): This is similar to the ‘REL1’ setting however it includes encoder acceleration. A message with value 64+n is sent out for every clockwise step (increment) and a message with value 64-n is sent out for every anti-clockwise step (decrement). The value n depends on how fast you rotate the encoder. It will be 1 when you rotate it slowly and get larger the faster you rotate it, meaning that you can scale the full range of a parameter with a small quick turn of
an encoder.

0-16K (14-bit mode): MIDI data values are transmitted as a 7-bit binary number, allowing a maximum value range of 0-127. The MIDI Specification allows for two MIDI control messages to be sent together where the data values form an MSB (most significant byte) and LSB (least significant byte) pair, making a 14-bit binary number and allowing a maximum value range of 0-16383. This is useful where fine control over a parameter is required, however the parameter you are controlling must be able to receive 14-bit MIDI values. If you want to send 14-bit values for fine control over a parameter then set DispType to ‘0-16K’. For CC controls, the MIDI Specification only allows for CC numbers 0 to 31 to be used in this way. Two CC messages are sent when the value of a parameter is changed – the first with the MSB value and the second with the LSB value. To enable the receiving device to distinguish between which CC message has the MSB value and which has the LSB value, the LSB value message is sent using a different CC number, calculated by adding 32 to the original CC number. Consequently CC numbers 32 to 63 are used for sending the LSB value in 0-16K (14-bit) mode. As an example, if a CC encoder has DispType set to ‘0-16K’ and CC Num set to 0 then, for each encoder step, two messages will be sent, a CC0 message with the MSB value and a CC32 message with the LSB value. The important point to note is that if an encoder has Control set to ‘CC’ and DispType set to ‘0-16K’ then CC Num should only be set from 0 through 31 and not higher.

APOT: This is a variation of ‘REL2’ and is the same system that is used by some other existing popular control surfaces. A message with value 0+n is sent out for every clockwise step (increment) and a message with value 64+n is sent out for every anti-clockwise step (decrement). The value n will equal 1 when you rotate the encoder slowly and increases as you rotate the encoder faster.

OK, i managed to get a script that (mostly) works as intended.
I re-used a Ramp-routine which David helped me with some time ago…
The script ‘collects’ the controller movement and sums up values of 0.01 stepwidth within a time period of 30ms and uses this sum as a relative value to set the widget. This means, the more steps are ‘collected’ on this time base, the bigger the increment will be.
The only issue i encountered with this script:
There are three widgets but i have defined only one variable for the stepwidth and its direction (+/-), so everything is fine, as long as only one knob is turned, but if i use two knobs at once and turn them in diffrent directions, the increment permanently switches between +/- depending on which knobs movement is ‘stronger’. Maybe the variable for the stepwidth should also be indexed in an array?
Anyway… i attached the rackspace to this post. Maybe it might be useful for somebody.relative_values.rackspace (13.0 KB)

1 Like

Thanks! I just found out that my Kenton Killamix mini can also do “relative values” I can set it for Doepfer mode and Ableton signed 7 bit mode; will try this out. (although Monday… upcoming show premiere this weekend)

Well, i wish you good luck then! :+1:
(If you have any questions, feel free to ask.)

1 Like

I will check out these racks and appreciate the help with that. But also just wanted to second the need for this feature.

It doesn’t seem that something changed in GP regarding relative mode ?

I now have a controller with knobs possibly working in two modes.

absolute mode: even if it is an endless knob, the controller keeps its value and the GP sync option doesn’t work with this controller value, such that the only option in this mode is to play with the catch/jump option, what I really don’t like for many reasons.

relative mode (MCP protocol CC16-23): clockwise it produces values ranging from 1 to 7 according to the speed and anti-clockwise it produces values ranging from 65 to 71 also related to the speed (I used the above script and replaced the line value - 128 by 64-value for values > 63).

Will GP scripting continue to be mandatory in this case ?

Relative mode is on our list but obviously I can’t say when it might be available

I am also thinking of this within RIG manager… not that easy…

I, too, would love to have relative mode support in Gig Performer. My home made controller has an array of 16 rotary encoders that I’ve coded to send relative CC info. I use it with Logic Pro to control plug-ins, but would now like to use it to control Gig Performer. I just purchased GP4.

Welcome @soundog! Until there is support for this, it may be a good introduction to GP Script, for you to develop a solution that works for you. A good starting point for us to help would be to show a screenshot of what the GP Global Midi Monitor (via Window menu) shows when you increment/decrement.

Hi @soundog, welcome to the GP community I would like to tell you that it is now possible out of the box in GP4, but I still have to tell you that GPScript is your friend in this case. @rank13 is right. :wink: