MIDI to Neopixel

Hi

I need some assistance expanding this working code to output to multiple shift registers

Thanks

#include <MIDI.h>
int latchPin = 8;
int clockPin = 12;
int dataPin = 11;
byte dataByte = B00000000;
MIDI_CREATE_DEFAULT_INSTANCE();

void setup() 
{
  pinMode(latchPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
  pinMode(dataPin, OUTPUT);
  MIDI.begin(MIDI_CHANNEL_OMNI);
  MIDI.setHandleControlChange(readmidicc);
  MIDI.turnThruOff();
}

void loop() 
{
  MIDI.read();
  output();
}
void readmidicc(byte channel, byte number, byte value) 
{
  if (value < 64) 
  {
    bitClear(dataByte, number-6); //-6 skips the first 6 channels sliders
  }
  else
  { 
    bitSet(dataByte, number-6); //-6 skips the first 6 channels sliders
  }
}

void output() 
{
  digitalWrite(latchPin, LOW);
  shiftOut(dataPin, clockPin, MSBFIRST, dataByte);
  digitalWrite(latchPin, HIGH);
}

Can you be more specific about what you want to do please.

Normally adding more shiftregisters is simply a matter of chaining them together. Like they show here http://www.lucidtronix.com/tutorials/40

Except do not connect a capacitor to the latch pin but connect it to the 5V pin instead, do it for each shift register.

Hi

This project is to add LEDs to indicate what Midi Command Channels are ON or OFF

This part runs when HIDI.h callback’s MIDI.setHandleControlChange
It takes the CC number and adjusts the corresponding bit
However I need to make this work with more than just 1 byte

I was thinking about using an array that contained 8 bytes or 64 bits, the using math to determine the byte to change and the bit to change

Number / 8 = BYTE remainder BIT eg CC30 / 8 = BYTE3 BIT6

if (value < 64) 
  {
    bitClear(dataByte, number-6); //-6 skips the first 6 channels sliders
  }
  else
  { 
    bitSet(dataByte, number-6); //-6 skips the first 6 channels sliders
  }

This part controls the shiftOut Function (I will make it run only when dataByte has changed)

Then shiftOut all the bits

{
  digitalWrite(latchPin, LOW);
  shiftOut(dataPin, clockPin, MSBFIRST, dataByte);
  digitalWrite(latchPin, HIGH);
}

I have done some simple math in decimal and have determined the constants now i just need assistance getting this into code. (If this is elegant and streamline enough)

number divided by 8 = BYTEnumber the leftover in decimal multiplied by 8 = BITnumber

EG. 33/8=4.125 BYTEnumber=4 0.124x8 = BITnumber = 1

You are going to need 16 shift registers to do this, are you sure you want to go that route. I would have thought the best way to do this would be to use a WS2812 LED strip, the hardware and software are simple.

But if you must go down the shift register route make a byte array 16 bytes long call it data, and then use your numbers to set or clear the appropriate bit.

bitSet (data[BYTEnumber]  , BITnumber);

Ok never though about ws2812 protocol. Where can I get ws2812 driver chips

You don’t need anything to drive them but a single output pin and a resistor. See this https://learn.adafruit.com/adafruit-neopixel-uberguide/the-magic-of-neopixels And the following pages.

and how do i put a neopixel into one of these?

Neopixel come in all sorts of form factors, including a standard 5mm through hole LED.

going to have to wait until my sample buttons show up to see which is going to work.

OK
So for testing I have 8 buttons with neopixel LEDs inside each. It is working well so far except if it is sent a midi cc “off” twice in a row it dims the led too much ->off completely
This is my current code for controlling the pixels but I want to call the ‘default’ color rather than use math when the button switches off.

This fuction sets the default color

void setstrips() {
    leds[0] = CRGB( 50, 0, 0);
    FastLED.show();
    delay(150);
    leds[1] = CRGB( 50, 25, 0);
    FastLED.show();
    delay(150);
    leds[2] = CRGB( 50, 50, 0);
    FastLED.show();
    delay(150);
    leds[3] = CRGB( 0, 50, 0);
    FastLED.show();
    delay(150);
    leds[4] = CRGB( 0, 50, 50);
    FastLED.show();
    delay(150);
    leds[5] = CRGB( 0, 0, 50);
    FastLED.show();
    delay(150);
    leds[6] = CRGB( 25, 0, 50);
    FastLED.show();
    delay(150);
    leds[7] = CRGB( 50, 0, 50);
    FastLED.show();
    delay(150);

This function does math when the button is pressed
This is what i want to call the default color instead of the /=4 math (or perhaps check if the led i’snt already low)

void MIDIinput(byte channel, byte number, byte value) {
  if (number<8) {
  if (value > 64) {
  leds[number] *=4;
  }else{
  leds[number] /=4;
  }
}}

If there is a better way than this I’m all ears

It is vertually impossible to debug code out of context with only part of the code being posted. However try this:-

void MIDIinput(byte channel, byte number, byte value) {
  if (number<8) {
  if (value > 64) {
  leds[number] *=4;
  }else{
  leds[number] =defaultValue[number];
  }
}}

Where defaultValue is an array of values you use for setting the value.

However the code originally is just setting one value in the leds array, I would have expected this to be three values one for each colour, and nowhere in the code do you call a display function for those LEDs. Which is why in the How to use this forum rules we ask you to post all your code.

Sorry
Here is the full code

/******************
 * 
 *   SETUP
 * 
 *******************/
 
#include <MIDI.h>
#include "Controller.h"
#include <FastLED.h>
#define DATA_PIN 12
#define NUM_LEDS 8
#define LED_TYPE WS2811      
MIDI_CREATE_DEFAULT_INSTANCE();
byte NUMBER_BUTTONS = 8;
byte NUMBER_POTS = 1;
byte NUMBER_MUX_BUTTONS = 0;
byte NUMBER_MUX_POTS = 0;
Pot PO1(A0, 0, 8, 2);
Pot *POTS[] {&PO1};
Button BU1(7, 1, 0, 2, 5 );
Button BU2(6, 1, 1, 2, 5 );
Button BU3(5, 1, 2, 2, 5 );
Button BU4(4, 1, 3, 2, 5 );
Button BU5(11, 1, 4, 2, 5 );
Button BU6(10, 1, 5, 2, 5 );
Button BU7(9, 1, 6, 2, 5 );
Button BU8(8, 1, 7, 2, 5 );
Button *BUTTONS[] {&BU1, &BU2, &BU3, &BU4, &BU5, &BU6, &BU7, &BU8};
Button *MUXBUTTONS[] {};
Pot *MUXPOTS[] {};
CRGB leds[NUM_LEDS];

void setstrips() {
    leds[0] = CRGB( 50, 0, 0);
    FastLED.show();
    delay(150);
    leds[1] = CRGB( 50, 25, 0);
    FastLED.show();
    delay(150);
    leds[2] = CRGB( 50, 50, 0);
    FastLED.show();
    delay(150);
    leds[3] = CRGB( 0, 50, 0);
    FastLED.show();
    delay(150);
    leds[4] = CRGB( 0, 50, 50);
    FastLED.show();
    delay(150);
    leds[5] = CRGB( 0, 0, 50);
    FastLED.show();
    delay(150);
    leds[6] = CRGB( 25, 0, 50);
    FastLED.show();
    delay(150);
    leds[7] = CRGB( 50, 0, 50);
    FastLED.show();
    delay(150);
   
  
}

void setup() {
  MIDI.begin(MIDI_CHANNEL_OMNI);
  MIDI.setHandleControlChange(MIDIinput);
  MIDI.turnThruOff();
  FastLED.addLeds<WS2811,DATA_PIN, RGB>(leds, NUM_LEDS);
  setstrips();
}

void loop() {
  if (NUMBER_BUTTONS != 0) updateButtons();
  if (NUMBER_POTS != 0) updatePots();
  if (NUMBER_MUX_BUTTONS != 0) updateMuxButtons();
  if (NUMBER_MUX_POTS != 0) updateMuxPots();
  MIDI.read();
  FastLED.show();
}

void MIDIinput(byte channel, byte number, byte value) {
  if (number<8) {
  if (value > 64) {
  leds[number] *=4;
  }else{
  leds[number] /=4;
  }
}}

void updateButtons() {

  // Cycle through Button array
  for (int i = 0; i < NUMBER_BUTTONS; i = i + 1) {
    byte message = BUTTONS[i]->getValue();

    //  Button is pressed
    if (message == 0) {
      switch (BUTTONS[i]->Bcommand) {
        case 0: //Note
          MIDI.sendNoteOn(BUTTONS[i]->Bvalue, 127, BUTTONS[i]->Bchannel);
          break;
        case 1: //CC
          MIDI.sendControlChange(BUTTONS[i]->Bvalue, 127, BUTTONS[i]->Bchannel);
          break;
        case 2: //Toggle
          if (BUTTONS[i]->Btoggle == 0) {
            MIDI.sendControlChange(BUTTONS[i]->Bvalue, 127, BUTTONS[i]->Bchannel);
            BUTTONS[i]->Btoggle = 1;
          }
          else if (BUTTONS[i]->Btoggle == 1) {
            MIDI.sendControlChange(BUTTONS[i]->Bvalue, 0, BUTTONS[i]->Bchannel);
            BUTTONS[i]->Btoggle = 0;
          }
          break;
      }
    }

    //  Button is not pressed
    if (message == 1) {
      switch (BUTTONS[i]->Bcommand) {
        case 0:
          MIDI.sendNoteOff(BUTTONS[i]->Bvalue, 0, BUTTONS[i]->Bchannel);
          break;
        case 1:
          MIDI.sendControlChange(BUTTONS[i]->Bvalue, 0, BUTTONS[i]->Bchannel);
          break;
      }
    }
  }
}
//*******************************************************************
void updateMuxButtons() {

  // Cycle through Mux Button array
  for (int i = 0; i < NUMBER_MUX_BUTTONS; i = i + 1) {

    MUXBUTTONS[i]->muxUpdate();
    byte message = MUXBUTTONS[i]->getValue();

    //  Button is pressed
    if (message == 0) {
      switch (MUXBUTTONS[i]->Bcommand) {
        case 0: //Note
          MIDI.sendNoteOn(MUXBUTTONS[i]->Bvalue, 127, MUXBUTTONS[i]->Bchannel);
          break;
        case 1: //CC
          MIDI.sendControlChange(MUXBUTTONS[i]->Bvalue, 127, MUXBUTTONS[i]->Bchannel);
          break;
        case 2: //Toggle
          if (MUXBUTTONS[i]->Btoggle == 0) {
            MIDI.sendControlChange(MUXBUTTONS[i]->Bvalue, 127, MUXBUTTONS[i]->Bchannel);
            MUXBUTTONS[i]->Btoggle = 1;
          }
          else if (MUXBUTTONS[i]->Btoggle == 1) {
            MIDI.sendControlChange(MUXBUTTONS[i]->Bvalue, 0, MUXBUTTONS[i]->Bchannel);
            MUXBUTTONS[i]->Btoggle = 0;
          }
          break;
      }
    }
    //  Button is not pressed
    if (message == 1) {
      switch (MUXBUTTONS[i]->Bcommand) {
        case 0:
          MIDI.sendNoteOff(MUXBUTTONS[i]->Bvalue, 0, MUXBUTTONS[i]->Bchannel);
          break;
        case 1:
          MIDI.sendControlChange(MUXBUTTONS[i]->Bvalue, 0, MUXBUTTONS[i]->Bchannel);
          break;
      }
    }
  }
}
//***********************************************************************
void updatePots() {
  for (int i = 0; i < NUMBER_POTS; i = i + 1) {
    byte potmessage = POTS[i]->getValue();
    if (potmessage != 255) MIDI.sendControlChange(POTS[i]->Pcontrol, potmessage, POTS[i]->Pchannel);
  }
}
//***********************************************************************
void updateMuxPots() {
  for (int i = 0; i < NUMBER_MUX_POTS; i = i + 1) {
    MUXPOTS[i]->muxUpdate();
    byte potmessage = MUXPOTS[i]->getValue();
    if (potmessage != 255) MIDI.sendControlChange(MUXPOTS[i]->Pcontrol, potmessage, MUXPOTS[i]->Pchannel);
  }
}

Thanks

To get it to work i had to declare the array like this

CRGB defaultColors[NUM_LEDS]{CRGB::Red, CRGB::Orange, CRGB::Yellow, CRGB::Lime, CRGB::Cyan, CRGB::Blue, CRGB::Purple, CRGB::DeepPink};

Now i would really like to run this as a for loop so that it is automatically scale-able

void setstrips() {
  leds[0] = defaultColors[0];
  leds[0] /= 4;
  FastLED.show();
  delay(150);
  leds[1] = defaultColors[1];
  leds[1] /= 4;
  FastLED.show();
  delay(150);
  leds[2] = defaultColors[2];
  leds[2] /= 4;
  FastLED.show();
  delay(150);
  leds[3] = defaultColors[3];
  leds[3] /= 4;
  FastLED.show();
  delay(150);
  leds[4] = defaultColors[4];
  leds[4] /= 4;
  FastLED.show();
  delay(150);
  leds[5] = defaultColors[5];
  leds[5] /= 4;
  FastLED.show();
  delay(150);
  leds[6] = defaultColors[6];
  leds[6] /= 4;
  FastLED.show();
  delay(150);
  leds[7] = defaultColors[7];
  leds[7] /= 4;
  FastLED.show();
  delay(150);
}

In place of the number in the array index, like leds[7], you use the loop variable of the for loop.

for( int i = 0; i < 8; i ++) {
leds[i ] = defaultColors[i ];
  leds[i ] /= 4;
  FastLED.show();
  delay(150);
}

Thanks for your help this is working well now