Fader pickup/catch mode

Hi all,

I am making a midi controller with faders, it currently works great but I would like to implement a feature that replicates some other midi controllers or software with a "takeover" or "catch" mode.

At the moment the faders are in "absolute" mode so if, for example, a fader is controlling a volume level of a synth and I have changed the volume level on the synth or change to another preset the value will jump to the fader value when I touch it. (with Arduino fader at 60%, volume on synth at 10% if I touch the Arduino fader the volume jumps from 10% to the Arduino fader value, close to 60%)

The synth outputs midi data of each parameter so I can store values from incoming midi messages to implement in the code.

I need the fader to not send any midi values if the received value is different to the last value sent by the fader and then when the fader passes the received value it defaults back to sending values.

I hope this makes sense, any help is much appreciated!

1 Like

Try again? I make no sense of that.

Does "passing" mean going past, either by coming up from below and going over, or coming down from above going under?

The fader can send values. How does it know about the setting on the other end so it can decide not to send?

It seems like the receiving entity (he who gets the fader value) needs to be modified, so it can get all the fading data in the world, but will not change until the current setting at the receiving end is "passed".

This if true is simple logic to implement in the receiver.

  if the setting is changed locally, go to filtering the fader values that come in


  if not filtering
    accept and go to the fader value received.

  if filtering and the received value is greater than the current setting
    start waiting for received values less than the current setting

  if filtering and the received value is less than the current setting
    start waiting for received values greater than the current setting

  if filtering and waiting
    if waiting for larger values and you get one
      stop filtering and set the current value to the fader
      
    if filtering for smaller values and you get one
      stop filtering and set the current value to the fader


Or say how I am confused.

a7

Thanks for the reply!

Does "passing" mean going past, either by coming up from below and going over, or coming down from above going under?

Yes correct.

The fader can send values. How does it know about the setting on the other end so it can decide not to send?

The other end is sending midi data into my Arduino controller via Midi DIN or Midi over USB, so I can use incoming midi to update a "received" variable for example and use that to compare with the fader value to decide if the fader should be outputting midi data or not (if the fader is at a different value to the received value).

This is a feature in quite a few music programs and here's an explanation of this "takeover" behaviour in Ableton. Ableton does the programming on its end but I need to implement it on the Arduino side, this should be possible as each parameter of the synth sends values over midi.

I can't program anything on the receiving side as it's a hardware synthesiser

Let's see if you can confuse me more. Low bar; confusion is my resting state.

OK, in this diagram, values are coming from somewhere ? box at left.

The fader can be manipulated and read or reacted to, central box.

Untouchable system (black box) at bottom gets either fader value or the mystery source of setting the same, er, setting.

You have said touching the fader causes the fader to send a message, I think. What causes new values to come in from the mystery source?

If I've got all that right, the logic I outlined goes in the double boxed box, where that box decides whether to pass along the fader value or the mystery received value.

In the double boxed box, you have to keep track of who's in charge, that is to say which input is passed along.

That box is either filtering or not, and if it is filtering it may get kicked into waiting for a value to exceed the current mark or for the value to go below the current mark.

When I understand perfectly or even a little better, I can make specific recommendations about coding the filter.

a7

1 Like

Sorry if I am unclear, the two devices are one Arduino board with faders and the other is a synthesiser. They are connected via MIDI.

The Arduino board currently sends midi CC values depending on fader position to the synthesiser which updates for example a volume parameter.

This works fine but the issue is that the volume parameter can be changed internally too on the synthesiser so if it is changed to say 0% and then the Arduino fader is moved from it's last position at say 100% then the Arduino will send a midi value which will cause the parameter to jump to a higher value. I need it to not send any values until it reaches the value that is currently set on the synth and THEN start sending values. So in the previous example I would need to move the fader all the way down to 0 for it to start sending out midi CC messages again.

The synth sends out midi values when any parameter is moved so I can store those values in the code in a variable and use them to compare with the current value of the fader.

Getting clearer, I got most of what you said and remain confident that somethig like my filter idea can be put somewhere in all this data flowing around.

Now I must ask if the opposite is not also a problem. That is to say, if the two means of setting one parameter for the black box are not to be considered symmetrical

If you've set the value from the mystery source, the fader should be respectful and not suddenly assert itself.

But do you also need or want…

If you've fiddled with the fader, the mystery source should be respectful and not suddenly assert itself.

Not that either the fader or mystery source can be silenced, just ignored.

So in the code there would be a concept of who's in charge, and who has to be watched to see if if passes the value of the source in charge to assert the newer value, and in that process also become the entity in charge.

Or say it is only bumping the fader that needs to be kept from introducing a rapid change to the fader value?

a7

OK we threw this together between hot dogs and hot dogging. It may not be at all what you are looking for. Even if it is it still has some wrinkles to be ironed out so there would be no audible glitch or pop.

We have two slide faders fighting to control one LED traveler on a strip.

One slide fader is "in control" until movement on the other brings its value close enough so it is allowed to take over.

Try it here:


Wokwi_badge Umbrella Academy Takeover Catch Demo


/ https://wokwi.com/projects/385841513818337281
// https://forum.arduino.cc/t/fader-pickup-catch-mode/1206227

# include <Adafruit_NeoPixel.h>

# define N_REAL   16
# define PIN      8

# define threshold  25    // to detect new value

// Global variables for lights and CAN communication
Adafruit_NeoPixel led(N_REAL, PIN, NEO_GRB + NEO_KHZ800);

void setup()
{
  Serial.begin(115200); Serial.println("first things first");

  led.begin();
  led.setPixelColor(1,  0xff0000);
  led.show();
  delay(777);
}

bool trackA = true;

void loop()
{
  static int lastA;
  static int lastB;

  static int output;

  bool newA = false;
  bool newB = false;

  int valA = analogRead(A0);
  int valB = analogRead(A1);

  if (abs(lastA - valA) > threshold) {
    newA = true;
    lastA = valA;

    if (abs(lastB - lastA) < threshold) trackA = true;
  }

  if (abs(lastB - valB) > threshold) {
    newB = true;
    lastB = valB;

    if (abs(lastB - lastA) < threshold) trackA = false;
  }

  led.clear();
  if (trackA) {
    output = valA;
    led.setPixelColor(valA / 64, 0xc00040); 
  }
  else {
    output = valA;
    led.setPixelColor(valB / 64, 0x404080); 
  }

  led.show();
}

void message(char *theMessage)
{
  static unsigned int counter;

  Serial.print(counter); Serial.print(" ");
  Serial.println(theMessage);

  counter++;
}

Lemme know if the tree I am barking up has bear up there in it anywhere.

a7

Hello my friend, thanks for that. Visually that is pretty much the functionality I'm talking about.

I created a different version here which demonstrates what I mean, it is not perfect and I'm sure there are better ways to do this but take a look?

Main problem is the fader A misses picking up the other value if it is moved too quickly past the value. Any ideas for alternative code that would pick up the value if the fader A was below fader B but is moved past the value of fader B and vice versa? Having a higher threshold helps but poses other issues.

I only have the minutes I spent playing with your wokwi.

You seem to have introduced the asymmetry I avoided. I can pickup/catch with on fader, but not the other.

Was that your intent?

I've played more with mine, it has some serious but fixable flaws. It just means tracking the state of the process with a bit more detail.

I do not have a concept of watching for it to come from below as opposed to above, so capture has the potential to glitch.

I do not do anything when the faders are equal, so if it possible to abandon a stuck value at the extremes.

And a few more subtle yet.

So a FSM (finite state machine) which did that and a few other details would be the way to code this.

Please say if you ultimately do want to have asymmetric behaviour. That one would have priority as seems is the case in your versoin.

Please say if these messages indicating the value of either input come regularly or only as the result of the senders having decided there is reason to do. Like if you only get a slide fader value if it is different, that is to say if the fader has been moved.

My current version assumes and may rely on the messages being continuously sent irrespective of any change on the input device.

a7

1 Like

Yes so the asymmetry is supposed to be like this as the fader B on the right is an endless encoder on the midi controlled device, it outputs midi when moved physically and takes over the control of the parameter. The fader A is a slider not an endless encoder so its position can't be updated.

A FSM seems to be the correct way of coding it to me but yes there are some annoying different behaviours depending on context. See below a description of the two states.

Absolute mode (default behaviour)

Fader A is sending Midi values out and these values are controlling the device parameter.
When the device is being controlled externally like this it outputs no midi values so the input value is not being updated. (This is where I am having issues as the value essentially sticks at the previous value Fader A caught it at)

Pick up mode

When the device's parameter is changed from the device itself it does send out the value via midi, this is what I am using to change from absolute to takeover mode.
At this point fader A should not send any midi values when it is being moved until its output value is equal or very close to the input value.

Having played around with the code a few times I think the difficulty lies in the device not sending out values in absolute mode.

OK.

The fact that the faders in the simulator are ideal helps. There will be no changes to their values that cannot be thought of as a new message from somewhere.

So I think the IPO model and an FSM would make this easier.

Input: see if there are new values from either source. develops value AAA, did change AAA, value BBB and did change BBB four variables.

Process: if there are any new values, and depending on which controller is currently in effect, calculate a new value to pass along, maybe, and change who is in effect, maybe.

Output: if there is a new value, from whoever said so, pass it out.

The IPO model is a good way to maintain your sanity with this kind of project. See the theory of it here if you haven't stumbled upon it so far, thank @paulpaulson:

If you can confirm this as a reasonable path forward, we (you) can start thinking about states that might be used for the FSM that will be used by the Process step.

I like the LCD you added, I'll switch to your hardware. I might add an LED or two, they can be easier to read/see for some kinds of reporting.

a7

2 Likes

OK, it's tired and I am getting late, so I'll just post the link to the wokwi simulation that I think is getting the functionality correct:

Umbrella Academy Pickup/Catch Demo

You have to click the encoder a few times before it amounts to needing to move the needle. Only because the LED strip is lower resolution.

I'll post the code or a cleaner version thereof at some point.

@lrssrl this really confused me until I realized that the rotary encoder can always move the value, and should. My original stab makes no sense unless the behaviour of the slide faders is identical.

So I got out a rotary encoder for the second input.

I used an FSM but had to violate strict IPO structure.

Say it is getting closer or not.

Added: A better tester than I found some errors and we fixed them, so far. She also motivated the addition of some nice LEDs.

a7

1 Like

She who should probably look for a job in QA has uncovered what I hope is the final flaw. I have to say she is enjoying this now more than I am. :expressionless:

The next to last version did not handle rapidly yanking the slide fader past the pickup/catch level.

I added buttons to make testing a yankation repeatable.

I also updated the code linked in #12 to allow instant movement of the slide fader to the extremes. Now when done the value is caught and picked up.

It is not clear if this would ever have happened IRL, but my friend was able to consistently make the previous version malfunction, and so far cannot with the new one.

Remains is the question of what happens should the two controls be manipulated at the exact same instant. I am tempted to say whatever happens is what happens and leave the matter there. But if I had a boss I can imagine she would want to sit down and figure out exactly what might should happen in that case. If both ask for an increase, a decrease or ask that the value change in different directions.

Once this version is deemed to have solved the problem, I think it can be simplified using the behaviour as an operating specification for starting over.

a7

1 Like

This is great and seems to be doing exactly what I need! I’m quite new to Arduino programming and reading your code is really helping me understand new things.

I will dig further into this tomorrow but if you think the code could be simplified I’d be keen to see how if/when you have time.

Thank you for your time so far I’ve already learnt a lot!

Me too, and THX. I do learn things here. About code, about projects and possibilities, about myself.

a7

I think someone might point out an extremely clever alternate logic. I don't do extreme cleverness.

Ideas for a very simpler approach have occured to me several times when I was falling asleep. So far I have been unable to remember any when I wake up. :expressionless:

So for now, other than rearranging things and figuring how to fit it into your own sketch, it be what it is.

I will think how it can be made into something that doesn't have to clutter up the main line of any code that needs to use something like it. That may depend on seeing your sketch or a smaller version of it with a big arrow pointing to exactly where the solution might be inserted, and how the soultion will have to be adjusted given that you are doing MIDI and mystery stuff, not just a silde fader and rotray encoder directly hook to an Arduino.

This would be fun with a motorized slide fader what could be updated when the rotary input is used.

a7

This feels like a problem that must have been solved elsewhere. Probably better and in a reusable and scalable fashion.

I haven't found any help googling, and I don't know enough about MIDI or, for that matter, designing good objects/classes whatever for handling something like this.

Therefore I invite @PieterP to take a look at the simulation in #7 and offer any suggestions. TIA.

I can't even find what a rotary encoder sends as MIDI messages; my code uses increment and decrement only, all and what one gets using a plain encoder at the lowest level of interfacing.

a7

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.