tttapa / Control-Surface

Arduino library for creating MIDI controllers and other MIDI devices.
GNU General Public License v3.0
1.23k stars 139 forks source link

potentiometers and multiplexer translation in daw #123

Open leshadave opened 4 years ago

leshadave commented 4 years ago

hello peter! I want to thank you for the work done! Now I am writing code for the midi controller, I encountered some problems in writing. The bottom line is that I already registered 2 encoders, and 16 buttons and potentiometers each through a multiplexer. The question is how to convert the data sent from the potentiometers in daw format. There is still a question about the FastLed library, it is how to register the w2812 LED on a certain midi message. thanks again

LukaszChrzanowski commented 4 years ago

What do You mean DAW format? If You use library corretly - You will send MIDI messages. That is enough to read it by DAW.

leshadave commented 4 years ago

What do You mean DAW format? If You use library corretly - You will send MIDI messages. That is enough to read it by DAW.

This post discussed https://github.com/tttapa/Control-Surface/issues/80 , only I need an array of potentiometers. through the multiplexer.

Ideally, it would turn out like this Min 0 (MSB: 0x00 LSB: 0x00) ~ Max 16383 (MSB: 0x7F LSB: 0x7F) When turned fully counterclockwise: 0 When turned fully clockwise: 16383 since 2 CC values ​​are sent by MSB and LSB

4dvn commented 4 years ago

hello peter! I want to thank you for the work done! Now I am writing code for the midi controller, I encountered some problems in writing. The bottom line is that I already registered 2 encoders, and 16 buttons and potentiometers each through a multiplexer. The question is how to convert the data sent from the potentiometers in daw format. There is still a question about the FastLed library, it is how to register the w2812 LED on a certain midi message. thanks again

Ws2812 work only on the arduino board, if you need the leds recive midi message from daw, just define the r,g,b array colors from start note is will bright from midi channel

tttapa commented 4 years ago

The DAW format depends on what DAW you're using.
You can use CCPotentiometer for 7-bit Control Change, and PBPotentiometer for 14-bit Pitch Bend.

14-bit CC is not supported out of the box, but you can easily add it. I'll see if I can post an example later tonight.

If you want to light FastLED LEDs on a MIDI message, you can either use the built-in classes as demonstrated in these examles: Note-FastLED & Note-FastLED-ColorMapper, or you can drive the strip manually, reading MIDI input using the different MIDI Input Elements.

tttapa commented 4 years ago

This should work after upgrading to c03f0783545aaa93c481e7d9575de0e543db8ec3:

#include <Control_Surface.h>

class CC14Potentiometer : public MIDIFilteredAnalog<ContinuousCCSender14<10>> {
  public:
    /** 
     * @brief   Create a new CC14Potentiometer object with the given analog pin
     *          and address.
     * 
     * @param   analogPin
     *          The analog input pin to read from.
     * @param   address
     *          The controller number [0, 31], MIDI channel 
     *          [CHANNEL_1, CHANNEL_16] and optional Cable Number [0, 15].
     */
    CC14Potentiometer(pin_t analogPin, const MIDIAddress &address)
        : MIDIFilteredAnalog(analogPin, address, {}) {}
}; 

USBDebugMIDI_Interface midi;

CC14Potentiometer pot = {A0, {MIDI_CC::Channel_Volume, CHANNEL_1}};

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

void loop() {
  Control_Surface.loop();
}
leshadave commented 4 years ago

Dear tttapa, could you write how it will be in the sketch? I just recently started programming. Just to make it a little clearer. Thanks. I already figured out the LEDs, but I still need help of the same nature: I put the shift register, everything seems to work correctly, the question is! Is it possible to make the LED light up a little, for example, at 5-10 percent of its brightness until the Midi message that it should be shining comes to it.

tttapa commented 4 years ago

Dear tttapa, could you write how it will be in the sketch?

Does the sketch above not work?

Is it possible to make the LED light up a little, for example, at 5-10 percent of its brightness until the Midi message that it should be shining comes to it.

Not in software, a shift register is a digital device, either the output is on, or it's not.
You could use an open-collector shift register, and add a high value resistor between each output pin and ground.

leshadave commented 4 years ago

Does the sketch above not work?

Peter, Everything works great. Sank a couple of potentiometers this way in his sketch

CC14Potentiometer pot0 = {A0, {MIDI_CC::Breath_Controller, CHANNEL_5} //FX1-1 }; CC14Potentiometer pot1 = {A1, {MIDI_CC::Foot_Controller, CHANNEL_6} //FX2-1 }; CC14Potentiometer pot2 = {A2, {MIDI_CC::Data_Entry_MSB, CHANNEL_5} //FX3-1 }; CC14Potentiometer pot3 = {A3, {MIDI_CC::Breath_Controller, CHANNEL_6} //FX1-2 }; CC14Potentiometer pot4 = {A4, {MIDI_CC::Foot_Controller, CHANNEL_5} //FX2-2 }; CC14Potentiometer pot5 = {A5, {MIDI_CC::Data_Entry_MSB, CHANNEL_6} //FX3-2 };

Not in software, a shift register is a digital device, either the output is on, or it's not. You could use an open-collector shift register, and add a high value resistor between each output pin and ground.

can I have a little more detail, which circuit to use? Or can this be done through ws2812? I wonder what can be done? I will just work at night, so I would like to see where to click) I do everything on Arduino Mega 2560

tttapa commented 4 years ago

To drive LEDs with an open-collector driver, you connect the anode of the LED to Vcc, and the cathode, through a resistor to the collector of the driver. If you connect a second resistor between the collector and ground, a small amount of current will flow, even if the driver is off, and the LED will light dimly.

You can use a WS2812 LED, you can dim it in software, but you might get in trouble with timing. If you drive multiple LEDs from a single AVR Arduino, you will lose MIDI bytes, which corrupts the data.
https://github.com/FastLED/FastLED/wiki/Interrupt-problems

If you use WS2812 LEDs, you'll most likely need something to diffuse the light, they are way too bright for simple indicators.

leshadave commented 4 years ago

To drive LEDs with an open-collector driver, you connect the anode of the LED to Vcc, and the cathode, through a resistor to the collector of the driver. If you connect a second resistor between the collector and ground, a small amount of current will flow, even if the driver is off, and the LED will light dimly.

It seems to be clear, the question is which driver to use for this? and is it possible to set not two LEDs, but to realize all this on one? Sorry for my ignorance (

tttapa commented 4 years ago

and is it possible to set not two LEDs, but to realize all this on one?

Do you mean you just want to dim a single LED? Using a shift register/LED driver, or connected to an Arduino pin directly? Shift registers and LED drivers usually come in packages with 8, 16 or 24 channels, but you don't have to use all channels, and you don't have to connect the extra resistor to all channels.

If you need more LEDs, you could use something like the TLC5926. (TI has many of these kinds of LED drivers, this was just the first one that showed up on Google.)

It should be noted that there are LED drivers with PWM control, like the TLC5940. These allow you to dim the LEDs in software. This might be overkill for your application, and it'll require some extra programming, but it might simplify the hardware side.

leshadave commented 4 years ago

I’ll say a little bit what I would like: For example, in the “idle” state when nothing is being sent to the shift register, the LEDs are lit at 5-10 percent, when for example I clicked on the button, the message midi note on came up, a certain LED turned on 100 percent and the rest remained burn at a percentage of 5-10. Well, something like that. That is, the use of LEDs on the shift register as a button illumination and an alarm for pressing it. At the moment I have https://www.ti.com/lit/ds/symlink/cd74hc595.pdf

If you need more LEDs, you could use something like the TLC5926. (TI has many of these kinds of LED drivers, this was just the first one that showed up on Google.)

just this shift register would ideally suit me for the outputs on the LEDs. Sorry if I don’t understand, because I’m doing everything through a translator.

It should be noted that there are LED drivers with PWM control, like the TLC5940. These allow you to dim the LEDs in software. This might be overkill for your application, and it'll require some extra programming, but it might simplify the hardware side.

Having read, I probably need this option. But you will need help writing code. Will you have such an opportunity?

tttapa commented 4 years ago

just this shift register would ideally suit me for the outputs on the LEDs. Sorry if I don’t understand, because I’m doing everything through a translator.

You cannot use standard 74HC595 shift registers for this trick because they have push-pull outputs. You need open-collector or open-drain outputs.
If you use shift registers without constant-current drivers, you need a current-limiting resistor for each LED, that's why I suggested the TLC5926.

But you will need help writing code. Will you have such an opportunity?

No, I don't have time to write code right now, and I don't have the hardware to test it.

You have to inherit from the ExtendedIOElement class, and implement all of the pure virtual functions in its interface, especially the analogWrite function.

https://github.com/tttapa/Control-Surface/blob/master/src/AH/Hardware/ExtendedInputOutput/ExtendedIOElement.hpp

You can use this library for example: https://github.com/PaulStoffregen/Tlc5940

Then you'll have to write your own version of the NoteLED class that uses analogWrite instead of digitalWrite, and doesn't turn off the LED completely when the note is disabled.

leshadave commented 4 years ago

Then you'll have to write your own version of the NoteLED class that uses analogWrite instead of digitalWrite, and doesn't turn off the LED completely when the note is disabled.

Dear Peter, if you can help, I’m ready to wait as long as I need, I would really like to implement this function, but I still have little experience in writing classes. I would be very grateful.

tttapa commented 4 years ago

You could try something like this: https://tttapa.github.io/Control-Surface-doc/Doxygen/dd/da5/Custom-Note-LED-Input-Element-Callback_8ino-example.html

leshadave commented 4 years ago

You could try something like this: https://tttapa.github.io/Control-Surface-doc/Doxygen/dd/da5/Custom-Note-LED-Input-Element-Callback_8ino-example.html

Yes Peter, this is what I wanted! Great, thanks. If I want to use them in this way via tlc5940 for example, I will have to connect the TLC5940.h library and prescribe?

CustomNoteValueLED led1 = { {note(A, 0), CHANNEL_1}, // Note C4 on MIDI channel 1 {10, 7}, // CustomLEDCallback constructor }; CustomNoteValueLED led2 = { {note(B, 0), CHANNEL_1}, // Note C4 on MIDI channel 1 {9, 7},

};

or how to write to an array? Same as in the shift register 74hc595? I just tried and failed ((

tttapa commented 4 years ago

Yes, out of the box, Control Surface doesn't know how to drive TLC5940 chips. You have to tell it how to do it by implementing the ExtendedIOElement interface for the TLC5940.

This should be pretty straightforward, as you only need to implement the begin and analogWrite methods for this use case.

Again, the chips I'm talking about are just to give an idea of what's possible, I've never tried any of them, and they might not be the best hardware for your use case.
Have a look at the TI product search tools before deciding on a chip: http://www.ti.com/power-management/led-drivers/signage-led-display-drivers/overview.html
I'm sure other manufactures have similar chips.

Also take into account Arduino usability, google for Arduino libraries first. Most of these chips are easy to drive without any libraries, but I wouldn't recommend that if you're a beginner.

Creating arrays is the same for all C++ objects, it's not specific to this library or even to Arduino.

CustomNoteValueLED leds[] = {
  {
    {note(A, 0), CHANNEL_1}, // Note C4 on MIDI channel 1
    {10, 7}, // CustomLEDCallback constructor
  },
  {
    {note(B, 0), CHANNEL_1}, // Note C4 on MIDI channel 1
    {9, 7},
  },
};

Each element of the array is initialized just like any other single object of that type, and you just add an extra pair of braces around the list of elements.

leshadave commented 4 years ago

This is a newbie, that's why I ask. Sorry again that I am really distracting you. But if we could help with tlc5940 with an array, as in a shift register, that would be great, just the delivery of some parts to our country is limited. I will be very grateful if you still help.

tttapa commented 4 years ago

I'm not sure what you mean by the array. What does it have to do with the TLC5940?

leshadave commented 4 years ago

for example, as with 74hc595, organize like in this array but with a function as you wrote above, in the sense that the LED lights up a little and when you press the button when the note is on, it lights up completely

SPIShiftRegisterOut<8> sreg = {
  10,       // Latch pin (ST_CP)
  MSBFIRST, // Byte order
};

using namespace MIDI_Notes;

NoteValueLED leds[] = {
  {sreg.pin(0), note(C, 4)}, // LED pin, address (note number, channel, cable)
  {sreg.pin(1), note(D, 4)}, //
  {sreg.pin(2), note(E, 4)}, //
  {sreg.pin(3), note(F, 4)}, //
  {sreg.pin(4), note(G, 4)}, //
  {sreg.pin(5), note(A, 4)}, //
  {sreg.pin(6), note(B, 4)}, //
  {sreg.pin(7), note(C, 5)}, //
};

In this topic of the question, you seem to have given some kind of example with tlc5940, but as I understand it, this is a single LED [https://github.com/tttapa/Control-Surface/issues/120]

Forgive me again for distracting you with your questions.

tttapa commented 4 years ago

Ah, I think I understand the confusion.

Organizing the NoteValueLEDs in an array is a separate issue from the TLC5940 (or 74HC595 for that matter).
You just have to tell the NoteValueLED object what pin to use. This is the first argument to the NoteValueLED constructor, i.e. sreg.pin(x) in the code you posted above. But it could just as well be a normal Arduino pin, such as 13 or A0.
NoteValueLED itself doesn't know (or care) what kind of pin it is, it treats all pins equally.

In the implementation of NoteValueLED's callback, at some point, it'll call a function like digitalWrite(pin, value). It is the digitalWrite function that determines what kind of pin it is, and then it takes the right steps to actually write the state to the pin.

As you can imagine, these steps are quite different depending on what kind of pin it is. For a built-in Arduino pin, it uses the standard Arduino functions, but for a shift register, it has to check what shift register it is, write the new state to the shift register's buffer, write the buffer to the shift register over SPI, and finally tell the shift register to output this new state.

If the digitalWrite doesn't know what kind of pin it is, you'll get an error, because it doesn't know what steps to take to actually write the state to the pin.

Luckily, the pin system (ExtIO) is fully extensible, so you can add new types of pins, for example, pins of an TLC5940. You can define a TLC5940 class, in the same way as the SPIShiftRegisterOut<8> class used in your example above.
I've posted some information about it in a previous reply.
The problem is that I can't really help you with the code because I don't have the right hardware to test it, and I've never used the TLC5940 library.

Basically all you have to do is inherit from the ExtendedIOElement class, and implement the necessary virtual methods:

// Definition
// ----------------------------------------------------------------------------
/**
 * @tparam N
 *              The number of daisy-chained TLC5940 chips.
 */
 template <uint8_t N>
 class TLC5490_Element : public StaticSizeExtendedIOElement<16 * N> {
   public:
     AnalogMultiplex(pin_t latchPin)
         : latchPin(latchPin) {}

     void pinMode(pin_t pin, PinMode_t mode) override {
        // Implement this
     }
     void digitalWrite(pin_t, PinStatus_t) override {
        // Implement this
     }
     int digitalRead(pin_t pin) override {
        // Implement this
     }
     analog_t analogRead(pin_t pin) override {
        // Implement this
     }
     void analogWrite(pin_t, analog_t) override {
        // Implement this
     }
     // Initialization
     void begin() override {
        // Implement this
        ::pinMode(latchPin, OUTPUT); 
        ::digitalWrite(latchPin, HIGH);
        // Note the :: ! 
        // (otherwise it'll call the member function or ExtIO function)
     }
     // Periodic updates (not needed for TLC5490)
     void update() override  {}

   private:
     pin_t latchPin;
     // Add other pins or state buffers if necessary
};

// Usage
// ----------------------------------------------------------------------------

TLC5490_Element tlc = {10};

NoteValueLED leds[] = {
  {tlc.pin(0), note(C, 4)}, // LED pin, address (note number, channel, cable)
  {tlc.pin(1), note(D, 4)}, //
  // ...
};

For the implementation of the methods above, you can use the Tlc5490 library discussed earlier. The pin parameter of these methods will always be a number between 0 and 16 * N - 1, indicating the pin of the chain of TLC5940s to read/write. For example, pin == 0 is the first pin of the first TLC5940 in the chain, pin == 1 is the second pin of that TLC5940, pin == 16 is the first pin of the second TLC5940, and so on.

leshadave commented 4 years ago

For the implementation of the methods above, you can use the Tlc5490 library discussed earlier. The pin parameter of these methods will always be a number between 0 and 16 * N - 1, indicating the pin of the chain of TLC5940s to read/write. For example, pin == 0 is the first pin of the first TLC5940 in the chain, pin == 1 is the second pin of that TLC5940, pin == 16 is the first pin of the second TLC5940, and so on.

Yes, I realized that, it should work out like something like this?

#include <Tlc5940.h>
#include <Control_Surface.h>

  USBMIDI_Interface midi;

using namespace MIDI_Notes;
 template <uint8_t N>
 class TLC5490_Element : public StaticSizeExtendedIOElement<16 * N> {
   public:
     AnalogMultiplex(pin_t latchPin)
         : latchPin(latchPin) {}

     void pinMode(pin_t pin, PinMode_t mode) override {
        // Implement this
     }
     void digitalWrite(pin_t, PinStatus_t) override {
        // Implement this
     }
     int digitalRead(pin_t pin) override {
        // Implement this
     }
     analog_t analogRead(pin_t pin) override {
        // Implement this
     }
     void analogWrite(pin_t, analog_t) override {
        // Implement this
     }
     // Initialization
     void begin() override {
        // Implement this
        ::pinMode(latchPin, OUTPUT); 
        ::digitalWrite(latchPin, HIGH);
        // Note the :: ! 
        // (otherwise it'll call the member function or ExtIO function)
     }
     // Periodic updates (not needed for TLC5490)
     void update() override  {}

   private:
     pin_t latchPin;
     // Add other pins or state buffers if necessary
};

// Usage
// ----------------------------------------------------------------------------

TLC5490_Element tlc = {10};

NoteValueLED leds[] = {
  {tlc.pin(0), note(C, 4), CHANNEL_1}, // LED pin, address (note number, channel, cable)
  {tlc.pin(1), note(D, 4), CHANNEL_1}, //
  // ...
};

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

void loop() {
 Control_Surface.loop(); 

}
}

if everything is correct, it gives an error in the sketch when checking

Arduino: 1.8.12 (Mac OS X), Плата:"Arduino Uno"

sketch_mar15a:14:30: error: 'PinMode_t' has not been declared
      void pinMode(pin_t pin, PinMode_t mode) override {
                              ^~~~~~~~~
sketch_mar15a:17:31: error: 'PinStatus_t' has not been declared
      void digitalWrite(pin_t, PinStatus_t) override {
                               ^~~~~~~~~~~
/Users/aleksejdavidovskij/Documents/Arduino/sketch_mar15a/sketch_mar15a.ino: In member function 'int TLC5490_Element<N>::AnalogMultiplex(AH::pin_t)':
sketch_mar15a:12:12: error: only constructors take member initializers
          : latchPin(latchPin) {}
            ^~~~~~~~
/Users/aleksejdavidovskij/Documents/Arduino/sketch_mar15a/sketch_mar15a.ino: At global scope:
sketch_mar15a:48:1: error: invalid use of template-name 'TLC5490_Element' without an argument list
 TLC5490_Element tlc = {10};
 ^~~~~~~~~~~~~~~
/Users/aleksejdavidovskij/Documents/Arduino/sketch_mar15a/sketch_mar15a.ino:48:1: note: class template argument deduction is only available with -std=c++1z or -std=gnu++1z
/Users/aleksejdavidovskij/Documents/Arduino/sketch_mar15a/sketch_mar15a.ino:9:8: note: 'template<unsigned char N> class TLC5490_Element' declared here
  class TLC5490_Element : public StaticSizeExtendedIOElement<16 * N> {
        ^~~~~~~~~~~~~~~
sketch_mar15a:51:4: error: 'tlc' was not declared in this scope
   {tlc.pin(0), note(C, 4), CHANNEL_1}, // LED pin, address (note number, channel, cable)
    ^~~
/Users/aleksejdavidovskij/Documents/Arduino/sketch_mar15a/sketch_mar15a.ino:51:4: note: suggested alternative: 'Tlc'
   {tlc.pin(0), note(C, 4), CHANNEL_1}, // LED pin, address (note number, channel, cable)
    ^~~
    Tlc
sketch_mar15a:52:4: error: 'tlc' was not declared in this scope
   {tlc.pin(1), note(D, 4), CHANNEL_1}, //
    ^~~
/Users/aleksejdavidovskij/Documents/Arduino/sketch_mar15a/sketch_mar15a.ino:52:4: note: suggested alternative: 'Tlc'
   {tlc.pin(1), note(D, 4), CHANNEL_1}, //
    ^~~
    Tlc
sketch_mar15a:54:1: error: could not convert '{<expression error>, CS::MIDI_Notes::note(0, 4), CS::CHANNEL_1}' from '<brace-enclosed initializer list>' to 'CS::NoteValueLED'
 };
 ^
sketch_mar15a:54:1: error: could not convert '{<expression error>, CS::MIDI_Notes::note(2, 4), CS::CHANNEL_1}' from '<brace-enclosed initializer list>' to 'CS::NoteValueLED'
sketch_mar15a:64:1: error: expected declaration before '}' token
 }
 ^
exit status 1
'PinMode_t' has not been declared

and I can’t understand where to substitute the initial value of the LED burning as you had in the example (I will indicate below)

// Instantiate the LED that will light up when middle C is playing
CustomNoteValueLED led = {
  {note(C, 4), CHANNEL_1}, // Note C4 on MIDI channel 1
  {3, 10},                 // CustomLEDCallback constructor
  //│  └─── intensity when off
  //└────── pin with the LED connected (PWM capable)
};
tttapa commented 4 years ago

To get rid of the PinMode_t errors, you have to download the latest version of the library. These types were added to comply with the latest Arduino API.

You have to add braces around the address. The address is a single parameter, you cannot pass the note number and the channel as separate parameters.

To change the intensity of the LED, you have to use CustomNoteValueLED, not NoteValueLED. You can just replace the pin number 3 with tlc.pin(x) in your previous code (given that you have implemented the begin, digitalWrite and analogWrite methods of the TLC5490_Element class correctly.

The following compiles correctly on 00e2543 for me:

#include <Tlc5940.h>
#include <Control_Surface.h>

USBMIDI_Interface midi;

template <uint8_t N>
class TLC5490_Element : public StaticSizeExtendedIOElement<16 * N> {
  public:
    TLC5490_Element(pin_t latchPin)
      : latchPin(latchPin) {}

    void pinMode(pin_t pin, PinMode_t mode) override {
      // Implement this
    }
    void digitalWrite(pin_t, PinStatus_t) override {
      // Implement this
    }
    int digitalRead(pin_t pin) override {
      // Implement this
    }
    analog_t analogRead(pin_t pin) override {
      // Implement this
    }
    void analogWrite(pin_t, analog_t) override {
      // Implement this
    }
    // Initialization
    void begin() override {
      // Implement this
      ::pinMode(latchPin, OUTPUT);
      ::digitalWrite(latchPin, HIGH);
      // Note the :: !
      // (otherwise it'll call the member function or ExtIO function)
    }
    // Periodic updates (not needed for TLC5490)
    void update() override  {}

  private:
    pin_t latchPin;
    // Add other pins or state buffers if necessary
};

// Usage
// ----------------------------------------------------------------------------

TLC5490_Element<1> tlc = {10};

using namespace MIDI_Notes;
NoteValueLED leds[] = {
  {tlc.pin(0), {note(C, 4), CHANNEL_1}}, // LED pin, address (note number, channel, cable)
  {tlc.pin(1), {note(D, 4), CHANNEL_1}}, //
  // ...
};

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

void loop() {
  Control_Surface.loop();
}
leshadave commented 4 years ago

To get rid of the PinMode_t errors, you have to download the latest version of the library. These types were added to comply with the latest Arduino API.

After installing the latest update, an error still appears, I tried to reinstall completely arduino ide from the official site and replaced the Arduino API, the result is the same.

The following compiles correctly on 00e2543 for me:

this example for me also compiles fine

You have to add braces around the address. The address is a single parameter, you cannot pass the note number and the channel as separate parameters.

To change the intensity of the LED, you have to use CustomNoteValueLED, not NoteValueLED. You can just replace the pin number 3 with tlc.pin(x) in your previous code (given that you have implemented the begin, digitalWrite and analogWrite methods of the TLC5490_Element class correctly.

please show an example Peter, I understand that I'm already starting to strain you very much, I'm sorry, my brain is already starting to boil

tttapa commented 4 years ago

After installing the latest update, an error still appears, I tried to reinstall completely arduino ide from the official site and replaced the Arduino API, the result is the same.

Did you install the latest master version? You can download it as a ZIP on the homepage of this repository, using the big green button in the top right.

this example for me also compiles fine

I didn't mean the example that was added in that commit, I just meant the commit itself. That's the one that works correctly for me. It was the latest commit on the master branch at that time. You need a recent master version for it to work.

The following compiles correctly for me on master, with Arduino IDE 1.8.9 and AVR Core 1.8.2. It's the same code as before but I added the CustomNoteValueLED example like you asked.

#include <Tlc5940.h>
#include <Control_Surface.h> // Include the Control Surface library

// Callback for Note or CC range or value input that turns on the LED at
// full brightness if the note or controller value is above the threshold,
// and turns on the LED at a lower brightness if the value is below the
// threshold.
class CustomLEDCallback : public SimpleNoteCCValueCallback {
 public:
  // Constructor
  CustomLEDCallback(pin_t ledPin, uint8_t lowBrightness)
    : ledPin(ledPin), lowBrightness(lowBrightness) {}

  // Called once upon initialization, set up the pin mode for the LED,
  // and output the initial value.
  void begin(const INoteCCValue &t) override {
    ExtIO::pinMode(ledPin, OUTPUT);
    updateAll(t);
  }

  // Called when the value of a note or controller value changes.
  // A MIDI Input Element can listen to a range of notes or
  // controllers, that's why the index of the note or controller
  // that changed is passed as a parameter.
  // In this example, only a single LED is used, so the index
  // doesn't really matter, it's used only to get the value of
  // the note/controller.
  void update(const INoteCCValue &t, uint8_t index) override {
    uint8_t value = t.getValue(index);
    bool state = value > threshold;
    state ? AH::ExtIO::digitalWrite(ledPin, HIGH)
          : AH::ExtIO::analogWrite(ledPin, lowBrightness);
  }

  // If you have an action in your custom callback that can be implemented more
  // efficiently when you need to update all values or outputs, you can override
  // the `updateAll` method.
  // It is called upon initialization (see the begin method) and when the bank
  // of a MIDI Input Element changes.
  // For example, turning off all LEDs in an LED strip can be done more
  // efficiently than turning off each LED individually.

 private:
  pin_t ledPin;
  uint8_t lowBrightness;
  const static uint8_t threshold = 0x3F;
};

// Create a type alias fore      the MIDI Note Input Element that uses
// the custom callback defined above.
using CustomNoteValueLED =
  GenericNoteCCRange<MIDIInputElementNote, 1, CustomLEDCallback>;

template <uint8_t N>
class TLC5490_Element : public StaticSizeExtendedIOElement<16 * N> {
  public:
    TLC5490_Element(pin_t latchPin)
      : latchPin(latchPin) {}

    void pinMode(pin_t pin, PinMode_t mode) override {}
    void digitalWrite(pin_t, PinStatus_t) override {
      // Implement this
    }
    int digitalRead(pin_t pin) override {}
    analog_t analogRead(pin_t pin) override {}
    void analogWrite(pin_t, analog_t) override {
      // Implement this
    }
    // Initialization
    void begin() override {
      // Implement this
      ::pinMode(latchPin, OUTPUT);
      ::digitalWrite(latchPin, HIGH);
      // Note the :: !
      // (otherwise it'll call the member function or ExtIO function)
    }
    // Periodic updates (not needed for TLC5490)
    void update() override  {}

  private:
    pin_t latchPin;
    // Add other pins or state buffers if necessary
};

// Usage
// ----------------------------------------------------------------------------

// Instantiate a MIDI over USB interface.
USBMIDI_Interface midi;

TLC5490_Element<1> tlc = {10};

using namespace MIDI_Notes;
// Instantiate the LED that will light up when middle C is playing
CustomNoteValueLED led = {
  {note(C, 4), CHANNEL_1}, // Note C4 on MIDI channel 1
  {tlc.pin(0), 10},        // CustomLEDCallback constructor
  //│           └─── intensity when off
  //└─────────────── pin with the LED connected (PWM capable)
};

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

void loop() {
  Control_Surface.loop();
}
leshadave commented 4 years ago

Did you install the latest master version? You can download it as a ZIP on the homepage of this repository, using the big green button in the top right.

Maybe I'm doing something wrong?

Arduino version 1.8.13

  1. I downloaded ArduinoCore-avr at this address https://github.com/arduino/ArduinoCore-avr/tree/api
  2. Navigated on his MacBook (/Applications/Arduino.app/Contents/Java/hardware/arduino/avr) and there I copied the entire contents of the zip archive with the replacement
tttapa commented 4 years ago

I meant the master version of Control Surface. Manually installing the AVR core is not necessary, it's best to use the board manager in the IDE.

leshadave commented 4 years ago

I meant the master version of Control Surface. Manually installing the AVR core is not necessary, it's best to use the board manager in the IDE.

I’m a fool)) I thought about something completely different. I updated your library and everything fell into place! Another such question when adding 2,3,4,5 LEDs I tried in a sketch

TLC5490_Element<1> tlc = {10};

using namespace MIDI_Notes;
// Instantiate the LED that will light up when middle C is playing
CustomNoteValueLED led = {
  {note(C, 4), CHANNEL_1}, // Note C4 on MIDI channel 1
  {tlc.pin(0), 10},
  {note(C, 4), CHANNEL_2},
  {tlc.pin(1), 10},   
};

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

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

but failed

tttapa commented 4 years ago

You have to create an array, you cannot initialize a single object with that many arguments.

CustomNoteValueLED leds[] = {
  {
    {note(C, 4), CHANNEL_1}, // Note C4 on MIDI channel 1
    {tlc.pin(0), 10},
  },
  {
    {note(C, 4), CHANNEL_2},
    {tlc.pin(1), 10},   
  },
};
leshadave commented 4 years ago

You have to create an array, you cannot initialize a single object with that many arguments.

As you just wrote, I tried to put the brackets in the wrong directions ((apparently the night is affecting, the last one is probably the question on this whole big "question" Am I connecting tlc5940 by this analogy? am I thinking right?

Basic Pin setup:
    ------------                                  ---u----
    ARDUINO   13|-> SCLK (pin 25)           OUT1 |1     28| OUT channel 0
              12|                           OUT2 |2     27|-> GND (VPRG)
              11|-> SIN (pin 26)            OUT3 |3     26|-> SIN (pin 11)
              10|-> BLANK (pin 23)          OUT4 |4     25|-> SCLK (pin 13)
               9|-> XLAT (pin 24)             .  |5     24|-> XLAT (pin 9)
               8|                             .  |6     23|-> BLANK (pin 10)
               7|                             .  |7     22|-> GND
               6|                             .  |8     21|-> VCC (+5V)
               5|                             .  |9     20|-> 2K Resistor -> GND
               4|                             .  |10    19|-> +5V (DCPRG)
               3|-> GSCLK (pin 18)            .  |11    18|-> GSCLK (pin 3)
               2|                             .  |12    17|-> SOUT
               1|                             .  |13    16|-> XERR
               0|                           OUT14|14    15| OUT channel 15
    ------------                                  --------

    -  Put the longer leg (anode) of the LEDs in the +5V and the shorter leg
         (cathode) in OUT(0-15).
    -  +5V from Arduino -> TLC pin 21 and 19     (VCC and DCPRG)
    -  GND from Arduino -> TLC pin 22 and 27     (GND and VPRG)
    -  digital 3        -> TLC pin 18            (GSCLK)
    -  digital 9        -> TLC pin 24            (XLAT)
    -  digital 10       -> TLC pin 23            (BLANK)
    -  digital 11       -> TLC pin 26            (SIN)
    -  digital 13       -> TLC pin 25            (SCLK)
    -  The 2K resistor between TLC pin 20 and GND will let ~20mA through each
       LED.  To be precise, it's I = 39.06 / R (in ohms).  This doesn't depend
       on the LED driving voltage.
    - (Optional): put a pull-up resistor (~10k) between +5V and BLANK so that
                  all the LEDs will turn off when the Arduino is reset.

    If you are daisy-chaining more than one TLC, connect the SOUT of the first
    TLC to the SIN of the next.  All the other pins should just be connected
    together:
        BLANK on Arduino -> BLANK of TLC1 -> BLANK of TLC2 -> ...
        XLAT on Arduino  -> XLAT of TLC1  -> XLAT of TLC2  -> ...
    The one exception is that each TLC needs it's own resistor between pin 20
    and GND.

    This library uses the PWM output ability of digital pins 3, 9, 10, and 11.
    Do not use analogWrite(...) on these pins.
tttapa commented 4 years ago

Yes, for the connections you'll have to follow the instructions of the Tlc5940 library.

leshadave commented 4 years ago

hello Peter, I hope you are all well! I am writing again about tlc5940, they recently sent me boards, connected them, checked with examples everything works, but I don’t want to be friends with the code that you helped me earlier. Is there any way to change another code? try another option, so to speak?

tttapa commented 4 years ago

but I don’t want to be friends with the code that you helped me earlier. Is there any way to change another code? try another option, so to speak?

What exactly do you mean? What doesn't work?

leshadave commented 4 years ago

I connected everything completely as it should, checked with an example everything is burning as it should (in terms of overflowing) I tried the one that you helped but alas, it did not start as it should. I'm talking about this code

#include <Tlc5940.h>
#include <Control_Surface.h> // Include the Control Surface library

// Callback for Note or CC range or value input that turns on the LED at
// full brightness if the note or controller value is above the threshold,
// and turns on the LED at a lower brightness if the value is below the
// threshold.
class CustomLEDCallback : public SimpleNoteCCValueCallback {
 public:
  // Constructor
  CustomLEDCallback(pin_t ledPin, uint8_t lowBrightness)
    : ledPin(ledPin), lowBrightness(lowBrightness) {}

  // Called once upon initialization, set up the pin mode for the LED,
  // and output the initial value.
  void begin(const INoteCCValue &t) override {
    ExtIO::pinMode(ledPin, OUTPUT);
    updateAll(t);
  }

  // Called when the value of a note or controller value changes.
  // A MIDI Input Element can listen to a range of notes or
  // controllers, that's why the index of the note or controller
  // that changed is passed as a parameter.
  // In this example, only a single LED is used, so the index
  // doesn't really matter, it's used only to get the value of
  // the note/controller.
  void update(const INoteCCValue &t, uint8_t index) override {
    uint8_t value = t.getValue(index);
    bool state = value > threshold;
    state ? AH::ExtIO::digitalWrite(ledPin, HIGH)
          : AH::ExtIO::analogWrite(ledPin, lowBrightness);
  }

  // If you have an action in your custom callback that can be implemented more
  // efficiently when you need to update all values or outputs, you can override
  // the `updateAll` method.
  // It is called upon initialization (see the begin method) and when the bank
  // of a MIDI Input Element changes.
  // For example, turning off all LEDs in an LED strip can be done more
  // efficiently than turning off each LED individually.

 private:
  pin_t ledPin;
  uint8_t lowBrightness;
  const static uint8_t threshold = 0x3F;
};

// Create a type alias fore      the MIDI Note Input Element that uses
// the custom callback defined above.
using CustomNoteValueLED =
  GenericNoteCCRange<MIDIInputElementNote, 1, CustomLEDCallback>;

template <uint8_t N>
class TLC5490_Element : public StaticSizeExtendedIOElement<16 * N> {
  public:
    TLC5490_Element(pin_t latchPin)
      : latchPin(latchPin) {}

    void pinMode(pin_t pin, PinMode_t mode) override {}
    void digitalWrite(pin_t, PinStatus_t) override {
      // Implement this
    }
    int digitalRead(pin_t pin) override {}
    analog_t analogRead(pin_t pin) override {}
    void analogWrite(pin_t, analog_t) override {
      // Implement this
    }
    // Initialization
    void begin() override {
      // Implement this
      ::pinMode(latchPin, OUTPUT);
      ::digitalWrite(latchPin, HIGH);
      // Note the :: !
      // (otherwise it'll call the member function or ExtIO function)
    }
    // Periodic updates (not needed for TLC5490)
    void update() override  {}

  private:
    pin_t latchPin;
    // Add other pins or state buffers if necessary
};

// Usage
// ----------------------------------------------------------------------------

// Instantiate a MIDI over USB interface.
USBMIDI_Interface midi;

TLC5490_Element<1> tlc = {10};

using namespace MIDI_Notes;
// Instantiate the LED that will light up when middle C is playing
CustomNoteValueLED led = {
  {note(C, 4), CHANNEL_1}, // Note C4 on MIDI channel 1
  {tlc.pin(0), 10},        // CustomLEDCallback constructor
  //│           └─── intensity when off
  //└─────────────── pin with the LED connected (PWM capable)
};

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

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

That is, it does not light up as it should at startup and does not respond to the midi message

tttapa commented 4 years ago

You have to implement the methods that say // Implement this.

leshadave commented 4 years ago

Peter, could you show how to do this? I ask for your help, I will be very grateful to you

tttapa commented 4 years ago

The following compiles, but I don't have the hardware to test it:

#include <Tlc5940.h>
#include <Control_Surface.h> // Include the Control Surface library

// Callback for Note or CC range or value input that turns on the LED at
// full brightness if the note or controller value is above the threshold,
// and turns on the LED at a lower brightness if the value is below the
// threshold.
class CustomLEDCallback : public SimpleNoteCCValueCallback {
 public:
  // Constructor
  CustomLEDCallback(pin_t ledPin, uint8_t lowBrightness)
    : ledPin(ledPin), lowBrightness(lowBrightness) {}

  // Called once upon initialization, set up the pin mode for the LED,
  // and output the initial value.
  void begin(const INoteCCValue &t) override {
    ExtIO::pinMode(ledPin, OUTPUT);
    updateAll(t);
  }

  // Called when the value of a note or controller value changes.
  // A MIDI Input Element can listen to a range of notes or
  // controllers, that's why the index of the note or controller
  // that changed is passed as a parameter.
  // In this example, only a single LED is used, so the index
  // doesn't really matter, it's used only to get the value of
  // the note/controller.
  void update(const INoteCCValue &t, uint8_t index) override {
    uint8_t value = t.getValue(index);
    bool state = value > threshold;
    state ? AH::ExtIO::digitalWrite(ledPin, HIGH)
          : AH::ExtIO::analogWrite(ledPin, lowBrightness);
  }

  // If you have an action in your custom callback that can be implemented more
  // efficiently when you need to update all values or outputs, you can override
  // the `updateAll` method.
  // It is called upon initialization (see the begin method) and when the bank
  // of a MIDI Input Element changes.
  // For example, turning off all LEDs in an LED strip can be done more
  // efficiently than turning off each LED individually.

 private:
  pin_t ledPin;
  uint8_t lowBrightness;
  const static uint8_t threshold = 0x3F;
};

// Create a type alias fore      the MIDI Note Input Element that uses
// the custom callback defined above.
using CustomNoteValueLED =
  GenericNoteCCRange<MIDIInputElementNote, 1, CustomLEDCallback>;

class TLC5490_Element : public StaticSizeExtendedIOElement<NUM_TLCS * 16> {
  public:
    void pinMode(pin_t, PinMode_t) override {}
    void digitalWrite(pin_t pin, PinStatus_t val) override {
      this->analogWrite(pin, val == LOW ? 0 : 255);
    }
    int digitalRead(pin_t) override {}
    analog_t analogRead(pin_t) override {}
    void analogWrite(pin_t pin, analog_t val) override {
      Tlc.set(pin, increaseBitDepth<12, 8, analog_t>(val));
      Tlc.update(); 
      // You could improve this by buffering, but this shouldn't be necessary
      // for your simple application
    }
    // Initialization
    void begin() override {
      Tlc.init();
    }
    // Periodic updates (not needed for TLC5490)
    void update() override  {}
};

// Usage
// ----------------------------------------------------------------------------

// Instantiate a MIDI over USB interface.
USBMIDI_Interface midi;

TLC5490_Element tlc;

using namespace MIDI_Notes;
// Instantiate the LED that will light up when middle C is playing
CustomNoteValueLED led = {
  {note(C, 4), CHANNEL_1}, // Note C4 on MIDI channel 1
  {tlc.pin(0), 10},        // CustomLEDCallback constructor
  //│           └─── intensity when off
  //└─────────────── pin with the LED connected (PWM capable)
};

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

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

This should work up to 689bd17cba8e912b2f98cbe1cf4f44a92277a3ec, later versions have some improvements in the ExtIO system.

leshadave commented 4 years ago

When compiling a sketch, it gives an error, updated your library to the newest one that currently exists

Arduino: 1.8.13 Hourly Build 2020/03/09 12:12 (Mac OS X), Плата:"Arduino Uno"

sketch_apr09c:73:10: error: 'void TLC5490_Element::update()' marked 'override', but does not override void update() override {} ^~ sketch_apr09c:82:17: error: cannot declare variable 'tlc' to be of abstract type 'TLC5490_Element' TLC5490_Element tlc; ^~~ /Users/aleksejdavidovskij/Documents/Arduino/sketch_apr09c/sketch_apr09c.ino:54:7: note: because the following virtual functions are pure within 'TLC5490_Element': class TLC5490_Element : public StaticSizeExtendedIOElement<NUM_TLCS * 16> { ^~~~~~~ In file included from /Users/aleksejdavidovskij/Documents/Arduino/libraries/Control-Surface-master/src/AH/Hardware/ExtendedInputOutput/StaticSizeExtendedIOElement.hpp:8:0, from /Users/aleksejdavidovskij/Documents/Arduino/libraries/Control-Surface-master/src/AH/Hardware/ExtendedInputOutput/AnalogMultiplex.hpp:9, from /Users/aleksejdavidovskij/Documents/Arduino/libraries/Control-Surface-master/src/Control_Surface.h:122, from /Users/aleksejdavidovskij/Documents/Arduino/sketch_apr09c/sketch_apr09c.ino:2: /Users/aleksejdavidovskij/Documents/Arduino/libraries/Control-Surface-master/src/AH/Hardware/ExtendedInputOutput/ExtendedIOElement.hpp:101:18: note: virtual void AH::ExtendedIOElement::pinModeBuffered(AH::pin_t, PinMode_t) virtual void pinModeBuffered(pin_t pin, PinMode_t mode) = 0; ^~~~~~~ /Users/aleksejdavidovskij/Documents/Arduino/libraries/Control-Surface-master/src/AH/Hardware/ExtendedInputOutput/ExtendedIOElement.hpp:122:18: note: virtual void AH::ExtendedIOElement::digitalWriteBuffered(AH::pin_t, PinStatus_t) virtual void digitalWriteBuffered(pin_t pin, PinStatus_t state) = 0; ^~~~~~~~ /Users/aleksejdavidovskij/Documents/Arduino/libraries/Control-Surface-master/src/AH/Hardware/ExtendedInputOutput/ExtendedIOElement.hpp:141:17: note: virtual int AH::ExtendedIOElement::digitalReadBuffered(AH::pin_t) virtual int digitalReadBuffered(pin_t pin) = 0; ^~~~~~~ /Users/aleksejdavidovskij/Documents/Arduino/libraries/Control-Surface-master/src/AH/Hardware/ExtendedInputOutput/ExtendedIOElement.hpp:162:18: note: virtual void AH::ExtendedIOElement::analogWriteBuffered(AH::pin_t, AH::analog_t) virtual void analogWriteBuffered(pin_t pin, analog_t val) = 0; ^~~~~~~ /Users/aleksejdavidovskij/Documents/Arduino/libraries/Control-Surface-master/src/AH/Hardware/ExtendedInputOutput/ExtendedIOElement.hpp:181:22: note: virtual AH::analog_t AH::ExtendedIOElement::analogReadBuffered(AH::pin_t) virtual analog_t analogReadBuffered(pin_t pin) = 0; ^~~~~~ /Users/aleksejdavidovskij/Documents/Arduino/libraries/Control-Surface-master/src/AH/Hardware/ExtendedInputOutput/ExtendedIOElement.hpp:196:18: note: virtual void AH::ExtendedIOElement::updateBufferedOutputs() virtual void updateBufferedOutputs() = 0; ^~~~~ /Users/aleksejdavidovskij/Documents/Arduino/libraries/Control-Surface-master/src/AH/Hardware/ExtendedInputOutput/ExtendedIOElement.hpp:207:18: note: virtual void AH::ExtendedIOElement::updateBufferedInputs() virtual void updateBufferedInputs() = 0; ^~~~~~~~ Несколько библиотек найдено для "SPI.h" Используется: /Users/aleksejdavidovskij/Documents/Arduino/libraries/SPI Не используется: /Users/aleksejdavidovskij/Library/Arduino15/packages/arduino/hardware/avr/1.8.2/libraries/SPI Несколько библиотек найдено для "SoftwareSerial.h" Используется: /Users/aleksejdavidovskij/Documents/Arduino/libraries/SoftwareSerial Не используется: /Users/aleksejdavidovskij/Library/Arduino15/packages/arduino/hardware/avr/1.8.2/libraries/SoftwareSerial exit status 1 'void TLC5490_Element::update()' marked 'override', but does not override

Этот отчёт будет иметь больше информации с включенной опцией Файл -> Настройки -> "Показать подробный вывод во время компиляции"

tttapa commented 4 years ago

Like I said, this only works up to 689bd17, later versions have some improvements in the ExtIO system.

I'll post a solution for the latest master version. Keep in mind that master will keep updating, so I might change the API before the following stable release.

leshadave commented 4 years ago

I understand you well, I am very grateful to you for your patience and your work done

tttapa commented 4 years ago

This should work for a0def40913b928f67846a0726b649dbdc6cfca44 and later:

#include <Tlc5940.h>
#include <Control_Surface.h> // Include the Control Surface library

// Callback for Note or CC range or value input that turns on the LED at
// full brightness if the note or controller value is above the threshold,
// and turns on the LED at a lower brightness if the value is below the
// threshold.
class CustomLEDCallback : public SimpleNoteCCValueCallback {
 public:
  // Constructor
  CustomLEDCallback(pin_t ledPin, uint8_t lowBrightness)
    : ledPin(ledPin), lowBrightness(lowBrightness) {}

  // Called once upon initialization, set up the pin mode for the LED,
  // and output the initial value.
  void begin(const INoteCCValue &t) override {
    ExtIO::pinMode(ledPin, OUTPUT);
    updateAll(t);
  }

  // Called when the value of a note or controller value changes.
  // A MIDI Input Element can listen to a range of notes or
  // controllers, that's why the index of the note or controller
  // that changed is passed as a parameter.
  // In this example, only a single LED is used, so the index
  // doesn't really matter, it's used only to get the value of
  // the note/controller.
  void update(const INoteCCValue &t, uint8_t index) override {
    uint8_t value = t.getValue(index);
    bool state = value > threshold;
    state ? AH::ExtIO::digitalWrite(ledPin, HIGH)
          : AH::ExtIO::analogWrite(ledPin, lowBrightness);
  }

  // If you have an action in your custom callback that can be implemented more
  // efficiently when you need to update all values or outputs, you can override
  // the `updateAll` method.
  // It is called upon initialization (see the begin method) and when the bank
  // of a MIDI Input Element changes.
  // For example, turning off all LEDs in an LED strip can be done more
  // efficiently than turning off each LED individually.

 private:
  pin_t ledPin;
  uint8_t lowBrightness;
  const static uint8_t threshold = 0x3F;
};

// Create a type alias fore      the MIDI Note Input Element that uses
// the custom callback defined above.
using CustomNoteValueLED =
  GenericNoteCCRange<MIDIInputElementNote, 1, CustomLEDCallback>;

class TLC5490_Element : public StaticSizeExtendedIOElement<NUM_TLCS * 16> {
  public:
    void pinMode(pin_t, PinMode_t) override {}
    void pinModeBuffered(pin_t, PinMode_t) override {}
    void digitalWriteBuffered(pin_t pin, PinStatus_t val) override {
      this->analogWriteBuffered(pin, val == LOW ? 0 : 255);
    }
    int digitalRead(pin_t) override {}
    int digitalReadBuffered(pin_t) override {}
    analog_t analogRead(pin_t) override {}
    analog_t analogReadBuffered(pin_t) override {}
    void analogWriteBuffered(pin_t pin, analog_t val) override {
      Tlc.set(pin, increaseBitDepth<12, 8, analog_t>(val));
      dirty = true;
    }
    // Initialization
    void begin() override {
      Tlc.init();
    }
    void updateBufferedOutputs() override {
      if (dirty) {
        Tlc.update(); 
        dirty = false;
      }
    }
    void updateBufferedInputs() override {}

  private:
    bool dirty = false;
};

// Usage
// ----------------------------------------------------------------------------

// Instantiate a MIDI over USB interface.
USBMIDI_Interface midi;

TLC5490_Element tlc;

using namespace MIDI_Notes;
// Instantiate the LED that will light up when middle C is playing
CustomNoteValueLED led = {
  {note(C, 4), CHANNEL_1}, // Note C4 on MIDI channel 1
  {tlc.pin(0), 10},        // CustomLEDCallback constructor
  //│           └─── intensity when off
  //└─────────────── pin with the LED connected (PWM capable)
};

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

void loop() {
  Control_Surface.loop();
}
leshadave commented 4 years ago

Everything seemed to work through TLC, but this is a joke, when starting, more than one LED does not light up and after sending the notes, it lights up and then works normally, as a matter of fact and it is assumed)) That is, 10 percent as I wrote above and when I click on note for all 100) Can I somehow start immediately on 10 percent LEDs? Or will you have to go through all the buttons yourself to start?

tttapa commented 4 years ago

Could you be more specific about what's wrong? I'll have a look at it tomorrow.

leshadave commented 4 years ago

I checked in the program, having registered the buttons and the output to the LEDs in advance, everything works fine! May I ask you a general question? Sorry to bother you. How to make sure that when you press the button, send note ON = 127 and when you release the button Note Off = 0 I tried all your examples already!

that's how I prescribe with a multiplexer:

const uint8_t velocity = 0x7F;
NoteButton FXbuttonsRight[] = { {mux.pin(0), {0x83, CHANNEL_6}, velocity}, //FX1 R {mux.pin(1), {0x84, CHANNEL_6}, velocity}, //FX2 R {mux.pin(2), {0x85, CHANNEL_6}, velocity}, //FX3 R {mux.pin(3), {0x76, CHANNEL_2}, velocity}, //Slip R {mux.pin(4), {0x35, CHANNEL_2}, velocity}, //Vinyl R {mux.pin(5), {0x33, CHANNEL_2}, velocity}, // Auto Loop R {mux.pin(6), {0x30, CHANNEL_2}, velocity}, // loop 1/2X {mux.pin(7), {0x31, CHANNEL_2}, velocity}, // loop 2X {mux.pin(8), {0x40, CHANNEL_2}, velocity}, // Asight 1 {mux.pin(9), {0x42, CHANNEL_2}, velocity}, // Asight 2

};

tttapa commented 4 years ago

You can define your own custom MIDI sender to do that:

#include <Control_Surface.h>

USBMIDI_Interface midi;

// A custom sender to use later. It has to declare two methods:
// - sendOn(MIDIAddress): will be called when the button is pressed
// - sendOff(MIDIAddress): will be called when the button is released
class CustomNoteSender {
  public:
    CustomNoteSender(uint8_t onVelocity, uint8_t offVelocity)
      : onVelocity(onVelocity), offVelocity(offVelocity) {}

    void sendOn(MIDIAddress address) {
      Control_Surface.sendNoteOn(address, onVelocity);
    }

    void sendOff(MIDIAddress address) {
      Control_Surface.sendNoteOff(address, offVelocity);
    }

  private:
    uint8_t onVelocity, offVelocity;
};

// Now tell the MIDIButton class template (included with the Control
// Surface library) that it has to use your custom sender class.
//
// We wrap it in another class so we can easily construct it later, 
// without having to write `MIDIButton<CustomNoteSender>` all the time,
// and so we have more control over the constructor arguments.
// The colon (:) indicates inheritance.
struct CustomNoteButton : MIDIButton<CustomNoteSender> {
  // Constructor
  CustomNoteButton(pin_t pin, MIDIAddress address, 
                   uint8_t onVelocity, uint8_t offVelocity)
    : MIDIButton(pin, address, {onVelocity, offVelocity}) {}
  //  ^~~~~~~~~~ Initialization of the base class MIDIButton
};

using namespace MIDI_Notes;

// Now we can instantiate an object of our custom class.
// The four arguments match the ones of the CustomNoteButton
// constructor we wrote a couple of lines back.
CustomNoteButton button = {
  2,            // button pin
  note(C, 4),   // MIDI address
  0x7F,         // on velocity
  0x00,         // off velocity
};

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

void loop() {
  Control_Surface.loop();
}
leshadave commented 4 years ago

By this principle will it work with a multiplexer? or will it need to be prescribed differently?

tttapa commented 4 years ago

pin_t is the type for all ExtIO pins. You can pass multiplexer pins to CustomNoteButton.

leshadave commented 4 years ago

Should it look like this in a sketch? I understand correctly? If with a multiplexer.

#include <Control_Surface.h>

USBMIDI_Interface midi;

// A custom sender to use later. It has to declare two methods:
// - sendOn(MIDIAddress): will be called when the button is pressed
// - sendOff(MIDIAddress): will be called when the button is released
class CustomNoteSender {
  public:
    CustomNoteSender(uint8_t onVelocity, uint8_t offVelocity)
      : onVelocity(onVelocity), offVelocity(offVelocity) {}

    void sendOn(MIDIAddress address) {
      Control_Surface.sendNoteOn(address, onVelocity);
    }

    void sendOff(MIDIAddress address) {
      Control_Surface.sendNoteOff(address, offVelocity);
    }

  private:
    uint8_t onVelocity, offVelocity;
};

// Now tell the MIDIButton class template (included with the Control
// Surface library) that it has to use your custom sender class.
//
// We wrap it in another class so we can easily construct it later, 
// without having to write `MIDIButton<CustomNoteSender>` all the time,
// and so we have more control over the constructor arguments.
// The colon (:) indicates inheritance.
struct CustomNoteButton : MIDIButton<CustomNoteSender> {
  // Constructor
  CustomNoteButton(pin_t pin, MIDIAddress address, 
                   uint8_t onVelocity, uint8_t offVelocity)
    : MIDIButton(pin, address, {onVelocity, offVelocity}) {}
  //  ^~~~~~~~~~ Initialization of the base class MIDIButton
};
CD74HC4067 mux = {
  2,               // Входной Пин Sig
  {4, 5, 6, 7},   // Адреса пинов Digital S0, S1, S2, S3
  // 7, // если нужен пин включения 
  };

using namespace MIDI_Notes;

// Now we can instantiate an object of our custom class.
// The four arguments match the ones of the CustomNoteButton
// constructor we wrote a couple of lines back.
  CustomNoteButton button[] = {
  {mux.pin(0), {0x83, CHANNEL_6}, 0x7F, 0x00},   //FX1 R
  {mux.pin(1), {0x84, CHANNEL_6}, 0x7F, 0x00},   //FX2 R
  {mux.pin(2), {0x85, CHANNEL_6}, 0x7F, 0x00},   //FX3 R
  {mux.pin(3), {0x76, CHANNEL_2}, 0x7F, 0x00},   //Slip R
  {mux.pin(4), {0x35, CHANNEL_2}, 0x7F, 0x00},   //Vinyl R
  {mux.pin(5), {0x33, CHANNEL_2}, 0x7F, 0x00},  // Auto Loop R
  {mux.pin(6), {0x30, CHANNEL_2}, 0x7F, 0x00},  // loop 1/2X 
  {mux.pin(7), {0x31, CHANNEL_2}, 0x7F, 0x00},  // loop 2X 
  {mux.pin(8), {0x40, CHANNEL_2}, 0x7F, 0x00},  // Asight 1
  {mux.pin(9), {0x42, CHANNEL_2}, 0x7F, 0x00},  // Asight 2

  };

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

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

And if I need to add a second multiplexer, will I have to copy the class two times?

tttapa commented 4 years ago

Should it look like this in a sketch? I understand correctly? If with a multiplexer.

Yes.

And if I need to add a second multiplexer, will I have to copy the class two times?

No, why would the number of multiplexers have anything to do with the number of class definitions?