Control-Surface icon indicating copy to clipboard operation
Control-Surface copied to clipboard

One RGB led VU. Different intensity for each segment.

Open MarcosGogo opened this issue 3 years ago • 6 comments

Hello.

First of all, sorry for any errors in English, my native language is Portuguese.

I really wanted to congratulate the creator of this incredible library. The Library is very incredible. Keep going on.

This is my first post on github. I am very amateur and I am still starting in the world of programming.

I am wanting to understand where I can start to implement two things with this library. And know if it's possible to do what I'm thinking.

  1. I would like to direct the 12 segments of the Mackie VU to only one simple 4pin RGB LED ( no shipset envolved), with differences in intensity and color for each of the 12 segment values ​​of the Mackie protocol. Below is a gif with a demonstration of the behavior I hope to achieve.

I would like to know where to start developing this idea. I don't know if I can set brightness and color for each segment of the Mackie Vu, its possible? I imagine that it may be possible to achieve this by configuring something by PWM pins or by intensity within the HSV color control. But I still don't know where to start.

Animated GIF-downsized

  1. This same RGB led that would read the VU signal from DAW, I wish it could be used for SOLO and MUTE. In this case when the channel is on solo or mute, the behavior of VU disappears to enter another color for SOLO and another for MUTE, while mute and solo are active. After the channel is no longer in SOLO or MUTE, the VU is active again.

All of these programming will be used with parameters of the MCU: MACKIE protocol.

I hope I haven't been too confused in my explanation. Any initial help is going to be really cool.

Thanks for all and continue with this incredible project.

MarcosGogo avatar Sep 25 '20 22:09 MarcosGogo

With the latest stable release, it's probably best to parse the MIDI data yourself, see https://tttapa.github.io/Control-Surface-doc/Doxygen/d1/d5d/MIDI-Input_8ino-example.html.

I've recently started reworking the MIDI input system to allow for things like this. The changes are on the new-input branch. With that version of the library, you can do something like this:

#include <Control_Surface.h>

USBMIDI_Interface midi;

struct MuteSoloVU_RGB : Updatable<> {
  MuteSoloVU_RGB(uint8_t track, 
                 PinList<3> rgbPins,
                 unsigned int decayTime = MCU::VUDecay::Default)
    : mute(MCU::MUTE_1 + track - 1),
      solo(MCU::SOLO_1 + track - 1), 
      vu(track, decayTime), 
      rgbPins(rgbPins) {}

  // Called periodically
  void update() override {
    // If any of the listeners received a new MIDI message:
    if (mute.getDirty() || solo.getDirty() || vu.getDirty()) {
      updateLEDs();
      mute.clearDirty(), solo.clearDirty(), vu.clearDirty();
    }
  }

  // Called once upon initialization
  void begin() override {
    /* nothing */
  }

  void updateLEDs() {
    if (mute.getValue())
      showLEDs(0x00, 0x00, 0xFF);
    else if (solo.getValue())
      showLEDs(0xFF, 0x00, 0xFF);
    else
      showLEDs(0x00, VU_PWM_lut[vu.getValue()], 0x00);
  }

  void showLEDs(uint8_t r, uint8_t g, uint8_t b) {
    analogWrite(rgbPins[0], r);
    analogWrite(rgbPins[1], g);
    analogWrite(rgbPins[2], b);
  }

  NoteValue mute, solo;
  MCU::VU vu;

  PinList<3> rgbPins;

  static const uint8_t VU_PWM_lut[13];
};

const uint8_t MuteSoloVU_RGB::VU_PWM_lut[] = {0,  1,  3,  5,   8,   14,  21,
                                              33, 50, 75, 113, 170, 255};

MuteSoloVU_RGB led = {
  1,                    // Track
  {4, 5, 6},            // RGB LED pins
  MCU::VUDecay::Default // VU decay time
};

void setup() {
  Control_Surface.begin();
}

void loop() {
  Control_Surface.loop();
}

You'll have to clone the library using git:

git clone https://github.com/tttapa/Control-Surface --branch new-input --recursive

The VU meter only shows different intensities of green, not orange or red, but that shouldn't be too hard to change yourself.

tttapa avatar Sep 27 '20 23:09 tttapa

Hi Pieter,

I really have no words to thank you for that quick answer, and for this amazing code. You really rocks, thanks so much Mr. Robot.

I am very happy to have been able to code, on my own, the colors orange and red for the last segments of the VU. It was a great step up for me, taking my condition as a true beginner.

The code its almost perfect, I just need to adjust some strange behavior i notice, and clarify some doubts that I still have.

Follow the working code below with the updates I made to obtain the colors orange and red, in addition to the green, which was already coded.

//
#include <Control_Surface.h>

USBMIDI_Interface midi;

struct MuteSoloVU_RGB : Updatable<> {
  MuteSoloVU_RGB(uint8_t track, 
                 PinList<3> rgbPins,
                 unsigned int decayTime = MCU::VUDecay::Default)
    : mute(MCU::MUTE_1 + track - 1),
      solo(MCU::SOLO_1 + track - 1), 
      vu(track, decayTime), 
      rgbPins(rgbPins) {}

  // Called periodically
  void update() override {
    // If any of the listeners received a new MIDI message:
    if (mute.getDirty() || solo.getDirty() || vu.getDirty()) {
      updateLEDs();
      mute.clearDirty(), solo.clearDirty(), vu.clearDirty();
    }
  }

  // Called once upon initialization
  void begin() override {
    /* nothing */
  }

  void updateLEDs() {
    if (mute.getValue())
      showLEDs(0x00, 0x00, 0xFF);
    else if (solo.getValue())
      showLEDs(0xFF, 0xFF, 0x00);
    else
      showLEDs(VU_PWM_lut_RED [vu.getValue()], VU_PWM_lut_GREEN [vu.getValue()], 0x00); 
  }

  void showLEDs(uint8_t r, uint8_t g, uint8_t b) {
    analogWrite(rgbPins[0], r);
    analogWrite(rgbPins[1], g);
    analogWrite(rgbPins[2], b);
  }

  NoteValue mute, solo;
  MCU::VU vu;

  PinList<3> rgbPins;

  static const uint8_t VU_PWM_lut_RED [12];
  static const uint8_t VU_PWM_lut_GREEN [12];
  static const uint8_t VU_PWM_lut_BLUE [12];
};

const uint8_t MuteSoloVU_RGB::VU_PWM_lut_RED [] = {0, 0,  0,  0,   0,   0,  0,
                                              0, 0, 0, 255, 255}; 
const uint8_t MuteSoloVU_RGB::VU_PWM_lut_GREEN [] = {0,  1,  3,  5,   8,   14,  50,
                                              75, 150, 200, 66, 0};
const uint8_t MuteSoloVU_RGB::VU_PWM_lut_BLUE [] = {0, 0,  0,  0,  0,  0,  0,
                                              0, 0, 0, 0, 0}; 

MuteSoloVU_RGB led = {
  1,                    // Track
  {4, 9, 10},            // RGB LED pins
  MCU::VUDecay::Default // VU decay time
};

void setup() {
  Control_Surface.begin();
}

void loop() {
  Control_Surface.loop();
}

Doubts and diagnoses

When I studied the code for the first time, I was surprised that you defined 13 variations of vu segments static const uint8_t VU_PWM_lut[13];

1 - From what I had read in other posts, the Mackie protocol was limited to 12. But after doing some tests on different DAWS, I noticed some differences, and maybe, why you defined 13 instead of 12. I suspect that the thirteenth segment is to trigger the Overload Clip. If that confirms, it's perfect for what I need.

I did a test with a static tone signal, so that there would be no variations in intensity in the VU, and I gradually increased the volume / intensity to notice the behavior of the changes of intensity and colors in the vu, and especially in what stage of Db , these exchanges took place.

Initially I set my code to have variations in green intensity in the first 12 segments and set the last segment (13) to the color red, to activate only when the 0Db / overload / clip was reached.

I tested this behavior on 3 DAW, using the Mackie protocol (Ableton Live, Reaper and Ardor).

At Ableton live, 13 segments were perfect. With the red LED of segment 13 turning on only after the VU overload and clip.

In Reaper and Ardor I noticed that, the red color of segment 13 activates before overloading, and just before reaching the top of the VU (+ 6db), the VU shuts down to the initial intensity. It is a strange behavior, but it must be due to the VUs of these programs going beyond 0Db, up to + 6db, different from Ableton.

What matters to me is that in Ableton it is correct, and that is what I was looking for.

2- Decay

I also noticed some differences in the behavior of the LED VU Decay

In Ardor, decay is more responsive, faster. And when an audio clip ends, the Vu will zero immediately without falling from Decay.

In Ableton, the Vu decay is a little slower and it seems that the leds follow the fall of Peak Vu, which in the ableton must be set for a high Hold Time and not the vu itself that goes down fast. I saw that there are some Decay settings inside your library, but I haven't found what parameters I can use other than "Default". I would also like to know if the "Default" means that the behavior of the VU will follow that used by DAW, without any adjustment by the library. My intention is to have Decay as responsive and fast as possible, or at least not slower than DAW. And it would be nice if I could choose between the decay to follow the peak hold or the vu itself. I believe that maybe this is a set to be done within Daw.

The issue

The only big problem I noticed, was related to a supposed flick on the LEDs.

I made the first testes with a song and I thought that the flickring could be the variation of segments. But then when I tested the VU with the static tone signal, I found it strange that the flick continued, even with the intensity frozen in the VU in only one segment.

Initially I thought it could be something in relation to the frequency and timer of the PWM pins, I am using a Teensy 2.0 with a 5mm anode RGB (Blue and Green 100 resistor and 150 for Red) on pins 4, 9 and 10 which according to the PJRC website says that the ideal frequency will be 3921.57 Hz.

But after I tested it with changing colors from one segment to another, I noticed an even stranger behavior. Which made me believe that the problem shouldn't be in relation to PWM frequency.

What happens is that when a segment, 12 for example, is turned on, it flashes simultaneously with the value of the previous segment, with 11 in this case. To be more clear, when segment 13 the only red in my code (Clip / overload) is triggered. Instead of the Led being only red, it is red with a green, from the previous segment, flashing simultaneously or alternately, its difficult to say.

I tested two segments in sequence, 12 and 13 for exemple, with the same values ​​of color and intensity and when it passes from one to the other, the flick disappears, as the same parameters are flashing. And it confirms that a segment is flashing with its own value added to that of the previous segment.

This is the big problem I would like to solve with this code so far, any help will be very welcome.

Extra Behavior code update

I had forgotten to mention one last behavior that I would like to have in this VU, MUTE and SOLO hierarchy. The way you programmed it, it was perfect for me. But I would like to add, that this hierarchy already programmed, works only when Rec Ready is activated. When it is not activated all the LEDs are off, as if the channel was disabled.

I tested some tweaks in the code to try something, but ended up finding several errors.

I imagine that this logic in this sector can make what I am looking for work. But I need to make calls right.

struct MuteSoloVU_RGB : Updatable<> {
  MuteSoloVU_RGB(uint8_t track, 
                 PinList<3> rgbPins,
                 unsigned int decayTime = MCU::VUDecay::Default)
    : rec(MCU::REC_RDY_1 + track - 1),
      mute(MCU::MUTE_1 + track - 1),
      solo(MCU::SOLO_1 + track - 1), 
      vu(track, decayTime), 
      rgbPins(rgbPins) {}

  // Called periodically
  void update() override {
    // If any of the listeners received a new MIDI message:
    if (mute.getDirty() || solo.getDirty() || vu.getDirty()) {
      updateLEDs();
      mute.clearDirty(), solo.clearDirty(), vu.clearDirty();
    }
  }

  // Called once upon initialization
  void begin() override {
    /* nothing */
  }

  void updateLEDs() {
    if (rec.getValue())
      showLEDs(VU_PWM_lut_RED [vu.getValue()], VU_PWM_lut_GREEN [vu.getValue()], 0x00);
    else if (mute.getValue())
      showLEDs(0x00, 0x00, 0xFF);
    else if (solo.getValue())
      showLEDs(0xFF, 0xFF, 0x00);
    else
      showLEDs(0x00, 0x00, 0x00);  // Or another code that disable the led.
  }

I ended up having errors in setting the REC to "REC_RDY_1". But I don't even know if this logic is correct to maintain the perfect hierarchy that was before with the addition of working only if REC_RDY is true.

Sorry for the giant message and the lack of clarity. Too many non-native languages for me. I hope I haven't confused it yet. I promise to improve my programming syntax to communicate better.

Thank you so much for everything. This library was the great gift and good news of 2020.

Best, Marcos

MarcosGogo avatar Oct 01 '20 08:10 MarcosGogo

  1. The maximum value of the VU meter is 12, so it has 13 states (you have to count 0). If you only have 12 elements in the lookup tables you'll go out of bounds.

  2. The decay rate used by the MCU protocol is 1.8s for all 12 segments, which is 150 ms per segment. This is rather slow, and not all DAWs support this, some expect the controller to not decay at all.

The flickering you're seeing could be caused by the DAW expecting the VU meters to hold instead of decaying automatically. You could try using MCU::VUDecay::Hold for the decay time. You can also use any integer value in milliseconds instead of these constants. It's the decay time for a single level.

I've never noticed the flickering, I'll try again later today and report back.

The MCU VU meter also has an "overload" flag, you can use vu.getOverload() in your code check it. Some DAWs don't seem to set this flag, though.

Finally, the code you posted is incomplete. Did you add a rec member variable? You have to check if it's dirty or not, and also clear the dirty flag afterwards, like with the other inputs (mute, solo, vu).
If you want to disable all LEDs if Rec/Rdy is off, you could use

  void updateLEDs() {
    if (!rec.getValue())
      showLEDs(0x00, 0x00, 0x00);
    else if (mute.getValue())
      showLEDs(0x00, 0x00, 0xFF);
    else if (solo.getValue())
      showLEDs(0xFF, 0x00, 0xFF);
    else
      showLEDs(0x00, VU_PWM_lut[vu.getValue()], 0x00);
  }

tttapa avatar Oct 01 '20 13:10 tttapa

Hi Pieter,

Thank you very much for responding so quickly.

Thanks for the explanation about the number of states in Vu. It's more clear to me now.

Good to know about vu.getOverload() flag. I will try to implement this in some way. But only after solving the other problems first.

The good news is that I think I was able to implement Rec_Rdy's behavior. Maybe it's not perfect yet, I still don't know if it's necessary to call him everywhere I put it in the code. But either way, it seems to be working.

About Decay Time. It seems that each DAW sends its own behavior. I think this has to do with whether DAW sends the update of the VU segments via PEAK VU or directly via the VU. On the Ableton and Reaper, it appears that the VU follows the dynamics of the PEAK VU, which has a slow decay time. In Ardor, it appears that the VU is updated by the normal VU and not by the PEAK VU, even though the Ardor visually has the PEAK VU with its decay time slower than the VU itself. I would like to obtain this faster and more precise behavior of Ardor, because this way the LED Vu becomes more responsive, generating a more accurate sensation of the current intensity of the input signal. But it seems that this is a setting that can only be done within the DAW when it is possible to change the behavior of the VU.

The real problem that remains is with the flick, which is still a little strange. When I tested MCU :: VUDecay :: Hold before implementing REC_RDY. Everything worked, the flick disappeared. And the Mute, Solo and VU leds were updating correctly.

Unfortunately, when I implemented Rec_Ready's behavior, the flick also disappeared, but it started to generate some updating problems between the functions. Usually saving an LED value when connecting and enabling some parameters, making the LED VU behavior no longer work, after some changes.

On the other hand, I did another test with the REC_RDY implemented, but going backwards with MCU :: VUDecay :: Hold to MCU :: VUDecay :: Default. With this code, which I will paste below, everything worked, except for the flick problem that came back. But the LED updates were correct, even with REC_RDY implemented.

One thing I found strange, is that in the MCU :: VUDecay :: function, the 'Hold' parameter is highlighted in blue, and the "Default" parameter is not highlighted. I believe that this must be normal, and it must be something of the language syntax that I don't understand yet.

What I would really like to have is this code below with 'MCU :: VUDecay :: Default' without the flick.

#include <Control_Surface.h>

USBMIDI_Interface midi;

struct MuteSoloVU_RGB : Updatable<> {
  MuteSoloVU_RGB(uint8_t track, 
                 PinList<3> rgbPins,
                 unsigned int decayTime = MCU::VUDecay::Default)
    : rec(MCU::REC_RDY_1 + track - 1),
      mute(MCU::MUTE_1 + track - 1),
      solo(MCU::SOLO_1 + track - 1), 
      vu(track, decayTime), 
      rgbPins(rgbPins) {}

  // Called periodically
  void update() override {
    // If any of the listeners received a new MIDI message:
    if ( rec.getDirty() || mute.getDirty() || solo.getDirty() || vu.getDirty()) {
      updateLEDs();
       rec.clearDirty(), mute.clearDirty(), solo.clearDirty(), vu.clearDirty();
    }
  }

  // Called once upon initialization
  void begin() override {
    /* nothing */
  }

void updateLEDs() {
    if (!rec.getValue())
      showLEDs(0x00, 0x00, 0x00);
    else if (mute.getValue())
      showLEDs(0x00, 0x00, 0x80);
    else if (solo.getValue())
      showLEDs(0x90, 0x90, 0x00);
    else
      showLEDs(VU_PWM_lut_RED [vu.getValue()], VU_PWM_lut_GREEN [vu.getValue()], VU_PWM_lut_BLUE [vu.getValue()]);
  }

  void showLEDs(uint8_t r, uint8_t g, uint8_t b) {
    analogWrite(rgbPins[0], r);
    analogWrite(rgbPins[1], g);
    analogWrite(rgbPins[2], b);
  }

  NoteValue rec, mute, solo;
  MCU::VU vu;

  PinList<3> rgbPins;

  static const uint8_t VU_PWM_lut_RED [13];
  static const uint8_t VU_PWM_lut_GREEN [13];
  static const uint8_t VU_PWM_lut_BLUE [13];
  
};

const uint8_t MuteSoloVU_RGB::VU_PWM_lut_RED [] = {1, 0,  0,  0,  0,   0,   0,  0,
                                              0, 0, 0, 255, 180}; 
const uint8_t MuteSoloVU_RGB::VU_PWM_lut_GREEN [] = {0, 1, 3,  4,  8,   14,   50,  75,
                                              100, 150, 200, 66, 0};
const uint8_t MuteSoloVU_RGB::VU_PWM_lut_BLUE [] = {1,  0,  0,  0,  0,  0,
                                              0, 0, 0, 0, 0, 0, 0};                                                                                            
                                            

MuteSoloVU_RGB led [] = {
  {1,                    // Track
  {4, 9, 10},            // RGB LED pins
  MCU::VUDecay::Default}, // VU decay time
  {2,                    // Track
  {12, 14, 15},            // RGB LED pins
  MCU::VUDecay::Default},
};

void setup() {
  Control_Surface.begin();
}

void loop() {
  Control_Surface.loop();
}

I still don't know how to find out and make sure the REC should be dirty or not.

Thank you very much for everything Pieter. You are helping me a lot.

MarcosGogo avatar Oct 01 '20 22:10 MarcosGogo

UPDATE

Hi Pieter,

I've been rethinking here, and I'm going to abandon this idea of ​​REC_RDY's behavior. So the implementation will be simpler.

I want to make it work with MCU::VUDecay::Default, and solve the Flick problem.

I strongly believe that if I can implement something like dotMode () that exists in the VULEDs class, maybe it would solve this problem, since apparently my problem with flick in MCU::VUDecay::Default seems to be an interleaving of the previous state with the current state of VU segments, it seems like a barMode () conflict problem for just one unit LED, instead of multiple leds for each state.. So if the VU is in dotMode () instead of barMode (), the previous led State will not exist, and the flick will probably disappear. I'm just not sure if it can implement something like dotMode () in this code with just one RGB LED.

You can disregard the code from the previous post, I will remove the behavior of REC_RDY. If you can help me to implement, if possible, dotMode () in this new code, I can test here to see if it works. And so I don't need to use MCU::VUDecay::Hold, which has some problems here. The problem I had with MCU::VUDecay::Hold, was that it works well only while the VU is active, receiving some signal. When I press stop on the DAW or the VU signal does not receive any signal, the LED has the last state frozen and does not return to the initial state. I believe that this is the expected behavior of MCU::VUDecay::Hold, and that is why I would like to implement it with the MCU::VUDecay::Default.

Thank you so much for everything. Below is the code I intend to use, lacking only the implementation of dotMode ()

#include <Control_Surface.h>

USBMIDI_Interface midi;

struct MuteSoloVU_RGB : Updatable<> {
  MuteSoloVU_RGB(uint8_t track, 
                 PinList<3> rgbPins,
                 unsigned int decayTime = MCU::VUDecay::Default)
    : mute(MCU::MUTE_1 + track - 1),
      solo(MCU::SOLO_1 + track - 1), 
      vu(track, decayTime), 
      rgbPins(rgbPins) {}

  // Called periodically
  void update() override {
    // If any of the listeners received a new MIDI message:
    if ( mute.getDirty() || solo.getDirty() || vu.getDirty()) {
      updateLEDs();
       mute.clearDirty(), solo.clearDirty(), vu.clearDirty();
    }
  }

  // Called once upon initialization
  void begin() override {
    /* nothing */
  }

void updateLEDs() {
    if (mute.getValue())
      showLEDs(0x00, 0x00, 0x80);
    else if (solo.getValue())
      showLEDs(0x90, 0x90, 0x00);
    else
      showLEDs(VU_PWM_lut_RED [vu.getValue()], VU_PWM_lut_GREEN [vu.getValue()], VU_PWM_lut_BLUE [vu.getValue()]);
  }

  void showLEDs(uint8_t r, uint8_t g, uint8_t b) {
    analogWrite(rgbPins[0], r);
    analogWrite(rgbPins[1], g);
    analogWrite(rgbPins[2], b);
  }

  NoteValue mute, solo;
  MCU::VU vu;

  PinList<3> rgbPins;

  static const uint8_t VU_PWM_lut_RED [13];
  static const uint8_t VU_PWM_lut_GREEN [13];
  static const uint8_t VU_PWM_lut_BLUE [13];
  
};

const uint8_t MuteSoloVU_RGB::VU_PWM_lut_RED [] = {1, 0,  0,  0,  0,   0,   0,  0,
                                              0, 0, 0, 255, 180}; 
const uint8_t MuteSoloVU_RGB::VU_PWM_lut_GREEN [] = {0, 1, 3,  4,  8,   14,   50,  75,
                                              100, 150, 200, 66, 0};
const uint8_t MuteSoloVU_RGB::VU_PWM_lut_BLUE [] = {1,  0,  0,  0,  0,  0,
                                              0, 0, 0, 0, 0, 0, 0};                                                                                            
                                            

MuteSoloVU_RGB led [] = {
  {1,                    // Track
  {4, 9, 10},            // RGB LED pins
  MCU::VUDecay::Default}, // VU decay time
  {2,                    // Track
  {12, 14, 15},            // RGB LED pins
  MCU::VUDecay::Default},
};


void setup() {
  Control_Surface.begin();
}

void loop() {
  Control_Surface.loop();
}

MarcosGogo avatar Oct 03 '20 00:10 MarcosGogo

One thing I found strange, is that in the MCU :: VUDecay :: function, the 'Hold' parameter is highlighted in blue, and the "Default" parameter is not highlighted. I believe that this must be normal, and it must be something of the language syntax that I don't understand yet.

The syntax highlighting of the Arduino IDE is really primitive, it doesn't analyze your actual code, it just recognizes some words, regardless of how they're used. Most of the time, you should completely ignore the colors in the IDE, it has nothing to do with how the compiler actually sees your code.

I'm unable to reproduce the flickering problem with the Tracktion DAW I'm using. The only solution I can think of is to use a longer decay time (e.g. 300 instead of MCU::VUDecay::Default).

To explain this more clearly, I think this is what's going on:
The DAW sends its meter values every 300ms, for example, and the decay time is 150ms. One division on the time axis below is 150ms. Then the flickering looks something like this:

level:
       3     ┌───────┐       ┌───────┐
       2     │       └───────┘       └───────┐
       1     │                               └───────┐
       0   ──┘                                       └───────
time:      ──┴───────┴───────┴───────┴───────┴───────┴───────
            (1)     (2)     (3)     (4)     (5)     (6)
  1. DAW: Set level 3
  2. Decay
  3. DAW: Maintain level 3
  4. Decay
  5. Decay
  6. Decay

The DAW doesn't expect the Arduino to decay at (2), but it does, so it decays to the level below it, then the DAW sends its next update at (3) and it goes back to the correct level. This repeats, resulting in a flicker.

Note: decay happens at regular intervals, determined by the decayTime argument. The timer is reset when the DAW updates the VU meter value.

I still don't know how to find out and make sure the REC should be dirty or not.

I'm not sure what you mean here. The NoteValue and VU classes receive values over MIDI and save them for you. "Dirty" means that they received a new value, so the stored value has changed, and you, the user of that value should read the value, and take some action, like updating an LED. To notify the NoteValue and VU classes that you have read this new value, you clear the "dirty" flag again.

I strongly believe that if I can implement something like dotMode () that exists in the VULEDs class, maybe it would solve this problem, since apparently my problem with flick in MCU::VUDecay::Default seems to be an interleaving of the previous state with the current state of VU segments, it seems like a barMode () conflict problem for just one unit LED, instead of multiple leds for each state.. So if the VU is in dotMode () instead of barMode (), the previous led State will not exist, and the flick will probably disappear.

Dot mode and bar mode are just display modes, they don't save any states, they display the current VU meter value only, and have no memory of the previous values or anything like that. The mode only determines whether all LEDs before the active LED are turned on (bar mode) or off (dot mode). This is the code used by the VULEDs class (indirectly):

https://github.com/tttapa/Control-Surface/blob/0395a0a99e333b7aaa35a7edcf8630c3a0da35a7/src/AH/Hardware/LEDs/DotBarDisplayLEDs.hpp#L40-L47

displayRange(0, value) turns on all LEDs from the first one up to the LED with index value.
displayDot(value-1) turns on the LED with index value-1.

For example, let's say that there are 12 LEDs, and value = 6.
Then displayRange(0, 6) will turn on the first six LEDs:
◉◉◉◉◉◉◎◎◎◎◎◎
And displayDot(5) turns on the sixth LED:
◎◎◎◎◎◉◎◎◎◎◎◎
(LED indices are zero-based)

tttapa avatar Oct 03 '20 11:10 tttapa