Go Down

Topic: MIDI to Neopixel (Read 855 times) previous topic - next topic

bigratty

May 27, 2018, 02:21 am Last Edit: Jul 03, 2018, 11:27 am by bigratty
Hi

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

Thanks

Code: [Select]
#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);
}

Grumpy_Mike

#1
May 28, 2018, 11:25 am Last Edit: May 28, 2018, 11:30 am by Grumpy_Mike
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.

bigratty

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

Code: [Select]


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

Code: [Select]

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

bigratty

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

Grumpy_Mike

#4
May 28, 2018, 03:35 pm Last Edit: May 28, 2018, 03:35 pm by Grumpy_Mike
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.

Code: [Select]

bitSet (data[BYTEnumber]  , BITnumber);

bigratty

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

Grumpy_Mike

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.

bigratty

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

Grumpy_Mike

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

bigratty

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

bigratty

#10
Jul 03, 2018, 11:26 am Last Edit: Jul 03, 2018, 11:34 am by bigratty
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
Code: [Select]
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)

Code: [Select]
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

Grumpy_Mike

#11
Jul 04, 2018, 05:14 am Last Edit: Jul 04, 2018, 05:20 am by Grumpy_Mike
It is vertually impossible to debug code out of context with only part of the code being posted. However try this:-
Code: [Select]
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.

bigratty

Sorry
Here is the full code

Code: [Select]
/******************
 *
 *   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);
  }
}

bigratty

Thanks

To get it to work i had to declare the array like this
Code: [Select]
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

Code: [Select]
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);
}

Grumpy_Mike

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

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

Go Up