Adding Adafruit LED Code to Teensy w/Controller

Status
Not open for further replies.

Synchrony

Active member
I've created a MIDI "Air Harp" instrument. Some prototype info:
Video: https://youtu.be/VMS8y9XyK0A
Images: https://imgur.com/5UsVyRW
https://imgur.com/H30AUpI
https://imgur.com/b1ulnFd
https://imgur.com/zaTGVYp

The current code:

Code:
int noteIsOn1;
int noteIsOn2;
int noteIsOn3;
int noteIsOn4;
int noteIsOn5;
int noteIsOn6;
int noteIsOn7;
int noteIsOn8;
int thresh;
int vel;

void setup() {

thresh = 400;
//thresh = constrain(thresh, 230, 232);
vel = (random(90,120));

}

void loop() {

/// Sensor 1
  if (noteIsOn1 == false) {
    if (analogRead(0) > thresh) {
      usbMIDI.sendNoteOn(60, random(90,120), 1);
      noteIsOn1 = true;
    }
  } else {
    if (analogRead(0) < thresh) {
      usbMIDI.sendNoteOff (60, 0, 1);
      noteIsOn1 = false;
    }
  }                 
/// Sensor 2
  if (noteIsOn2 == false) {
   if (analogRead(1) > thresh) {
      usbMIDI.sendNoteOn(62, random(90,120), 1);
      noteIsOn2 = true;
    }
  } else {
    if (analogRead(1) < thresh) {
      usbMIDI.sendNoteOff (62, 0, 1);
      noteIsOn2 = false;
    }    
  }
/// Sensor 3
  if (noteIsOn3 == false) {
    if (analogRead(2) > thresh) {
      usbMIDI.sendNoteOn(64, random(90,120), 1);
      noteIsOn3 = true;
    }
  } else {
    if (analogRead(2) < thresh) {
      usbMIDI.sendNoteOff (64, 0, 1);
      noteIsOn3 = false;
    }    
  }
  /// Sensor 4
  if (noteIsOn4 == false) {
    if (analogRead(3) > thresh) {
      usbMIDI.sendNoteOn(65, random(90,120), 1);
      noteIsOn4 = true;
    }
  } else {
    if (analogRead(3) < thresh) {
      usbMIDI.sendNoteOff (65, 0, 1);
      noteIsOn4 = false;
    }    
  }
    /// Sensor 5
  if (noteIsOn5 == false) {
    if (analogRead(4) > thresh) {
      usbMIDI.sendNoteOn(67, random(90,120), 1);
      noteIsOn5 = true;
    }
  } else {
    if (analogRead(4) < thresh) {
      usbMIDI.sendNoteOff (67, 0, 1);
      noteIsOn5 = false;
    }    
  }
  /// End Sensor
      /// Sensor 6
  if (noteIsOn6 == false) {
    if (analogRead(5) > thresh) {
      usbMIDI.sendNoteOn(69, random(90,120), 1);
      noteIsOn6 = true;
    }
  } else {
    if (analogRead(5) < thresh) {
      usbMIDI.sendNoteOff (69, 0, 1);
      noteIsOn6 = false;
    }    
  }
  /// End Sensor
        /// Sensor 7
  if (noteIsOn7 == false) {
    if (analogRead(6) > thresh) {
      usbMIDI.sendNoteOn(70, random(90,120), 1);
      noteIsOn7 = true;
    }
  } else {
    if (analogRead(6) < thresh) {
      usbMIDI.sendNoteOff (70, 0, 1);
      noteIsOn7 = false;
    }    
  }
  /// End Sensor
        /// Sensor 8
  if (noteIsOn8 == false) {
    if (analogRead(7) > thresh) {
      usbMIDI.sendNoteOn(72, random(90,120), 1);
      noteIsOn8 = true;
    }
  } else {
    if (analogRead(7) < thresh) {
      usbMIDI.sendNoteOff (72, 0, 1);
      noteIsOn8 = false;
    }    
  }
  /// End Sensor
  while (usbMIDI.read()) {}
  delay(5);

}

I'll try to make the code more elegant at some point.

Next step that I need help on:

I'm replacing the sticks in the prototype with clear tubes. Then I'm putting 3-9W LEDs at the bottom of the tubes. The idea is that the tubes will be one color when idle and another when activated.

Here's a CAD image:
yd82Lt3.png

I've bought this LED controller from adafruit:
https://www.adafruit.com/product/1429

As I understand it, I need to include the TLC5947 library in my above code. I think I can figure out the setup code. I'm not positive how to use the loop code. Here's a template of what each note/tube code would look like:

Code:
/// Sensor 1
  if (noteIsOn1 == false) {
    if (analogRead(0) > thresh) {
      usbMIDI.sendNoteOn(60, random(90,120), 1);
      ///[B]INSERT CODE TO ACTIVATE LED COLOR FOR noteIsOn1=true[/B]
      noteIsOn1 = true;
    }
  } else {
    if (analogRead(0) < thresh) {
      usbMIDI.sendNoteOff (60, 0, 1);
      ///[B]INSERT CODE TO ACTIVATE LED COLOR FOR noteIsOn1=false[/B]
      noteIsOn1 = false;
    }
  }

I'm sure it's simple, but I'm not understanding what to use based on Adafruit's sample code.

Thanks much for any help!
 
You have a choice... you can figure out how to program that part for SPI control or you can figure out how to control LED load currents via transistor switches.

No offence, but your programming skills appear a bit on the novice side. But if you go that way you need to learn how to use the library that supports SPI
https://www.pjrc.com/teensy/td_libs_SPI.html




If you have any electronics background (or are keen to learn) you might find it easier to use 9 digital pins to control each LED by driving the pin HIGH and LOW as needed (depending on if you are sourcing or sinking current and whether you are using a BJT or JFET/MOSFET to switch the circuit -- there are dozens of circuit variations that do this -- below is one).
ZK60L.png

If you were going for two full octaves then the SPI would be a more compelling option as you can't afford 2 pins for every note.



Regarding making your code more elegent… (when you are ready...)

Your code could benefit from using arrays if you are doing the same thing with code on multiple objects.

Since the pin is the only difference your code for each pin can be consolidated into a single 'for' loop.
Code:
for (int i = 0; i < 8; i++){
    if (noteIsOn[i] == false) {
        if (analogRead(i) > thresh) {
            usbMIDI.sendNoteOn(note[i], random(90,120), 1);
            noteIsOn[i] = true;
        }
    } else {
        if (analogRead(i) <= thresh){
            usbMIDI.sendNoteOff (note[i], 0, 1);
            noteIsOn[i] = false;
        }
    }
}

The local variable i is an index from zero to one less than the number of elements. Therefore the last element in note[] has an index of 7.

The loop increments the index from 0 to 7 (last value "<8" - the number of elements in the array)

You would need to declare the variables as arrays instead of as separate scalar values.

So this:
Code:
int noteIsOn1;
int noteIsOn2;
int noteIsOn3;
int noteIsOn4;
int noteIsOn5;
int noteIsOn6;
int noteIsOn7;
int noteIsOn8;

Becomes this:
Code:
int noteIsOn[8];

And you would need to configure a variable with all the note numbers you want to use
Code:
int note[8] = {60,62,64,65,67,69,71,72};

Any you would likely do the same with pin numbers for the analog pins and LED pins.

e.g.
int ANALOG_PINS[A_PINS] = {A0,A1,A2,A3,A5,A6,A7,A8,A9};
Note these don't have to be in order -- I've skipped A4 but as long as I've wired it that way it's fine. Very handy once you need specific pins for specific things.
Your code actually relies a convention with analogRead that 1 = A1 but if you are explicitly listing pins it's best to call analog pins with the A# designation.

With time you could figure out how to store the rate of change from values that didn't cross the threshold to generate a proportional velocity value when they do... (sample the values a regular intervals and use the difference to calculate a velocity value for the note on message).

Interesting project... Nice to see modest early ambitions with plans for incremental improvement instead of trying to do everything at once.

I'm happy to help with MIDI and basic programming stuff but I don't claim any expertise on SPI and really have only minimal electronics knowledge but there are lots of great people here that can help (provided you put in effort from your end).
 
Copy example global variable stuff over to your program.
Copy example setup stuff into your program setup()
Wherever you want to light up your lights in your code just put:
tlc.setLED(x, r, g, b);
tlc.write();

Where x is the led you want to light up and r,g,b are the red green blue values you want.
x could be 1 to 8 I think and rgb probably 0-255. That’s my guess based on a look at example while I wait for my car to be serviced.
 
D'oh… didn't notice the colour comments... kinda undermines my comments on direct control.

Unless you really just want to alternate, in which case you can use the same signal and source one and sink the other to alternate the colour.

If you want RGB LEDs on each you might consider smart pixel elements.
 
Ooh. Oddson got me thinking. I don’t think that pwm controller can drive any significant power. I .09W maybe. Better check that. My apologies if you already have that covered.
 
Thanks for the coding tips on the 'for' loop @oddson! I should have prefaced that I haven't coded in about 10 years and should be considered a newbie. But I would consider myself a MIDI expert (lifelong synth player, since before MIDI) :).

My nephew, who is an engineer, is handling the electronics and building the frame. After I built the prototype I asked him for help to take it to the next level. He 3D printed the caps for the tubes and they look like they came from a legit manufacturer. Anyway, he picked out the controller for the LEDs. From what I read, "You can drive multiple LEDs in series, with a V+ anode supply of up to 30V." I think we're okay if I understand that right. We'll find out when the LEDs and the controller come in today.

I mainly need help with the coding, which my nephew doesn't do very much. But this is really simple, so thanks @Gibbedy for this:

tlc.setLED(x, r, g, b);
tlc.write();

Nice! I will see this all the way through, because we're using this instrument as our centerpiece for an epic Christmas song at my church. We were going to use a laser harp, but that's a huge animal to try to tackle this year. It morphed into this "Air Harp."

Thanks again and any other input greatly appreciated.
 
Apologies... yet again not reading carefully

The controller should be fine and the library doesn't look difficult to use.

Gibbedy's comments appear correct except the colour values are 12 bit values (stored as type uint16_t)

Ooh. Oddson got me thinking. I don’t think that pwm controller can drive any significant power. I .09W maybe. Better check that. My apologies if you already have that covered.
That would be the spec 'Constant output sink current'? Says 30 mA. which is about 0.1W at 3.3 v.

I have no clue it this will be sufficient for your project. I'm have very little LED display experience other than indicators.

If you are interested I could help get you velocity control based on time between crossing two thresholds.

Velocity could be mapped inversely proportional to the time between crossing lower to upper threshold.
 
Last edited:
Okay, we finally have the sensor harp very close to finished, but I can't get my head around the LED programming. The "harp" has 8 three-foot acrylic tubes on a frame positioned vertically. The tops of the tubes have the sensors that translate to a MIDI note when you put your hand over it. That part works fine. Inside each tube is an LED strip attached to the ADAFRUIT tlc5947 (https://www.adafruit.com/product/1429). By this evening everything will be hooked up and ready to program, but I'm still lost on the LED programming. I'm not understanding how each tube of LEDs can be addressed. We aren't using analog as I thought we were, so now I have to understand PWM.

Here are the basic instructions: https://learn.adafruit.com/tlc5947-...out/programming#tlc5947-library-reference-5-6. I need to think of each of the 8 tubes as a channel. If each tube is , then is a channel is the pin number some kind of factor of 3? "lednum = LED number (channel number of the "red" pin divided by 3)".

I'm so lost. Any help greatly appreciated. Here is the current code:

Code:
// LED
#include "Adafruit_TLC5947.h"
#define NUM_TLC5974 1
#define data   4
#define clock   5
#define latch   6
#define oe  -1  // set to -1 to not use the enable pin (its optional)
Adafruit_TLC5947 tlc = Adafruit_TLC5947(NUM_TLC5974, clock, data, latch);
// END LED

// HARP
int noteIsOn[8]; 
int note[8] = {60,62,64,65,67,69,71,72}; //MIDI Notes
int thresh;
int vel;
int chan;
// END HARP
 

void setup() {

// LED
  Serial.begin(9600);
  
  Serial.println("TLC5974 test");
  tlc.begin();
  if (oe >= 0) {
    pinMode(oe, OUTPUT);
    digitalWrite(oe, LOW);
  }
// END LED

// HARP
thresh = 400; //Threshold of sensor
vel = (random(100,127)); //MIDI velocity
chan=1; //MIDI channel
// END HARP

}

void loop() {   

   // SENSOR IS ON
for (int i = 0; i < 8; i++){
    if (noteIsOn[i] == false) {
        if (analogRead(i) > thresh) {
            usbMIDI.sendNoteOn(note[i], vel, chan);
            noteIsOn[i] = true;

// ADD LED NOTE ON COLOR CODE HERE     
 
        }

    } else {

   // SENSOR IS OFF  
        if (analogRead(i) <= thresh){
            usbMIDI.sendNoteOff (note[i], 0, chan);
            noteIsOn[i] = false;

// ADD LED NOTE OFF COLOR CODE HERE

        }
    }
}
}
 
I'm going to give @Gibbedy's code a try when the hardware is ready (sometime tonight). In this code, a tubes should be blue when not activated and red when it is. Fingers crossed:

Code:
// LED
#include "Adafruit_TLC5947.h"
#define NUM_TLC5974 1
#define data   4
#define clock   5
#define latch   6
#define oe  -1  // set to -1 to not use the enable pin (its optional)
Adafruit_TLC5947 tlc = Adafruit_TLC5947(NUM_TLC5974, clock, data, latch);
// END LED

// HARP
int noteIsOn[8]; 
int note[8] = {60,62,64,65,67,69,71,72}; //MIDI Notes
int thresh;
int vel;
int chan;
// END HARP
 

void setup() {

// LED
  Serial.begin(9600);
  
  Serial.println("TLC5974 test");
  tlc.begin();
  if (oe >= 0) {
    pinMode(oe, OUTPUT);
    digitalWrite(oe, LOW);
  }
// END LED


// HARP
thresh = 400; //Threshold of sensor
vel = (random(100,127)); //MIDI velocity
chan=1; //MIDI channel
// END HARP
}

void loop() {   

   // SENSOR IS ON
for (int i = 0; i < 8; i++){
    if (noteIsOn[i] == false) {
        if (analogRead(i) > thresh) {
            usbMIDI.sendNoteOn(note[i], vel, chan);
            noteIsOn[i] = true;
// LED RED   
      tlc.setLED(i, 4095, 0, 0);
      tlc.write();  
// END LED
        }
    } else {

   // SENSOR IS OFF  
        if (analogRead(i) <= thresh){
            usbMIDI.sendNoteOff (note[i], 0, chan);
            noteIsOn[i] = false;
// LED BLUE   
      tlc.setLED(i, 0, 0, 4095);
      tlc.write();  
// END LED
        }
    }
}
}
 
Status
Not open for further replies.
Back
Top