Convert HSL to RGB or Frequency to Color
Hello! I am a college student working on a final project that uses an WS2811 300 LED strip and an Arduino Uno to mimic a piano. So when a key is pressed, a specific color and position on the strip will light up. So far, by watching some youtube videos, I was able to map the colors properly but they are in hsl and in order to send the data to the LED strip it needs to be RGB. I am not sure if doing this in Max or Arduino would be easier but any help would be greatly appreciated! Here is what I have so far in Max.
Edit: I "finished" this project in Dec 2018. Trying to remember what I did and see if I can get it working again. Edits are me getting rid of txt files and properly adding the max patches.
That's the way I'd probably do it, but here's another way without using the swatch-- inside the hsl->rgb subpatch. As you can see it's pretty clumsy -- convert list to jitter matrices, then convert using the hsl2rgb, then reformat back into a list using jit.spill, but I guess there's no UI overhead which may be an issue if you're doing rapid/multiple changes.
Thank you! I finally got the strip to output the specific color I want based on what key I pressed. There is however a major delay when pressing the next key. Hopefully I will be able to figure out why and speed it up a bit but for now I am slowly working on integrating the positioning on the strip. Here is what I have so far including the Arduino code.
I've never used arduino, so can't help you there, but I made a couple of changes to your patch-- I replaced a couple of pak objects with pack-- otherwise you have multiple redundant calculations occurring. Also altered some connections that were duplicating processes or not doing anything. Also I noticed a problem that in the original subpatch that I sent you (again repeated redundant calculations), so it's now I fixed in this newer version. Hope it's of some use anyway.
I thing the request is a bit diffeent, leds on the strip should
light up depending on which key has been pressed, and mybe rgb
should represent Velocity ?
Than a question would be about polyphony etc etc.
Like if key 48 with velo 127 than Led 48 rgb 255 0 0 ?
One would want to avoid sending 100 messages for 100 LEDs,
but maybe have a code in arduino that clears all but the ones
which one wants to light.
So maybe clear all, light xy
Just an idea
just by looking at your arduino code it looks like you can do that-- it should be very easy-- instead of using a for loop to activate all the leds then just respond to an individually addressed led :
strip.setPixelColor(i, r0, b0, g0);
where the i variable would be mapped from the midi note number somehow (probably in the max patch)
Thank you!
I don't know how I didn't see that. I think it was because I was skipping a step and looking for a way for the light to turn on, only when pressed, and turn off when not pressed (which is where I believe velocity comes in). But so far here is the working patch and code. Right now it turns on the specific LED location, but does not turn it off.
if you're using a midi keyboard, normally velocity zero means note-off. the easiest way for you would be to map velocity to lightness (in HSL) then convert to rgb, then voila, the LCDs will turn themselves off without you having to alter your arduino code. To emulate this in max with the kslider, just change it to polyphonic mode (see kslider help file)-- here is a modified patch:
Boy does it get glitchy, but it works! Thank you all for the help! It lags a lot at times and some notes stay lit until pressed again but you should have seen my face when I hooked it up to my midi keyboard.
The Arduino code is the same but here is the final Max patch, I just added the hook-up to my controller.
if it's glitchy maybe optimize a little by getting rid of UI objects (see below)
note also I got rid of your mapping from midi to hz to hue-- that was redundant just map straight from MIDI to hue using scale
also make sure Max is set to overdrive
Both FastLED and NeoPixel libraries are very fast, so if it all is glitchy
You have to optimize the flow.
1 deactivate dtr
2 speed midi to color conversion using simpler than all that jitter stuff.
strip expects 0 -255 values, so why not use that from the beginning.
swatch has compatibility mode 0 - 255 if You need that to decide on color
You could even build a list with RGB values mapped to each note
and store it in coll, if You want something different for each note.
Velocity could multiply RGB values for intensity.
You're coll idea really interests me but I have no idea how to do so. I was looking into coll but if I am correct, I would need 120 values in coll for 10 octaves of notes. How would I go about calling on that data when I need it?
coll is as simple as it can be.
it has following structure :
Address comma data semicolon
example :
1, 255 0 0 ;
when You send coll message "1" it outputs the data.
In case of note number 48, coll coud have :
48, 160 0 160;
You can simply edit plain text and have coll read it or embed
in a patcher, or enter values in coll directly.
velocity could scale the RGB values to control brightness :
So I leave it to Your imagination how to combine note numbers and RGB Values.
Using modulo % for per octave RGB ?
0r having really as many values in as expected notes ?
Or a combination of some kind ?
That would definitely work for one of my patches. I will post when I am done. But would it be possible to look for RGB values within coll and output the index (or in this case, key)?
Here is the finished patch. It is untested but I think it should work. I also included the values in my coll but for some reason they won't save when I close so every time I reopen the patch, the values need to be reentered.
simply send coll embed 1 message, to make it store values in the patcher.
RGB can also be index, just make it symbol ;
"200 150 0", 48;
that would output note 48 if "200 150 0" index is called
That all is visible in coll help file and refeence
Thank you! This is all working well. Multiple notes can be pressed without a crash. But once a color is turned on, it won't turn off. Any ideas on how to fix it? This is the updated patch.
You must turn "Notes" or "LEDs" off using
velocity.
I included that in first example.
If You don't want to scale RGB values, then at
least multiply them by 1 or 0 .
If You get trouble with tracing too many held-released notes,
than look into objects like flush .
Works like a charm again except that it keeps crashing when playing chords. By crashing I mean the LEDs sustain the color but won't accept anymore input for about 10 seconds. Could you explain a bit more about flush. I know how it works but I am confused on how it would solve the chord problem. I have also had the thought that it may be an Arduino code issue instead.
Either You are overloading serial output from max,
or arduino code can't cope with messages You send.
First step is to make sure that messages from max
don't get sent repeated to serial object.
That can happen when one collects data into a list.
If You upload max patch and arduino code, I'll have a look into it.
But learn to select all in the patch, copy compressed and paste
here.
Arduino sketch can be uploaded as file.
I usually debug max - arduino serial issues by sending messages
from max and echoing them back.
I would do that first without any LED code in the sketch.
Oh, thank you! I was wondering why it kept copying as a text file
The arduino code I haven't changed since the beginning. I included it and my patch below. But I figured it had something to do with code, I am just not sure how to attack it and do some debugging.
The arduino code is as simple as it looks,
but if You digg into library files, You will see that
execution of the messages has it's timing and interrupts.
That is what makes it difficult to deal with.
To simplify it - I believe that data comming from serial port
are getting dropped because execution of events for LED strip
is in main loop, which makes loop to wait till it's done to proceed.
I mean strip(show);
----------
Now what to do about it ?
there are several options to try.
You will have to accept a bit of latency when several notes are being played.
One could slowdown midi flow a bit to do so and reduce number of voices.
Here is one example of LED Strip code using fast led library :
-------------------------
#include "FastLED.h"
#define DATA_PIN 3
#define NUM_LEDS 100
CRGB leds[NUM_LEDS];
void setup() {
FastLED.addLeds<WS2811, DATA_PIN, RGB>(leds, NUM_LEDS);
Serial.begin(115200);
}
void loop() {
if (Serial.available() > 0) {
int LEDno = Serial.parseInt();
int ledR = Serial.parseInt();
int ledG = Serial.parseInt();
int ledB = Serial.parseInt();
if (Serial.read() == '\n') {
noInterrupts();
leds[LEDno].setRGB(ledR, ledG, ledB);
FastLED.show();
delayMicroseconds(50); // latch and reset WS2811
interrupts();
}}}
-----------------
I used this patch a while ago in different context and
setting noInterrupts(); execute the led code interrupts(); in loop
made it more responsive.
But I did not have midi notes as source but some other sensors,
so input order was better regulated.
---------
Maybe You could search in neopixel library docs
what one has to do to keep timing uninterrupted.
Another option would be to use predefined colors in Arduino sketch
and send only single numbers for each key on and key off.
That would decrease the serial traffic somewhat.
So far there has been a lot of lag with the current patch. Mainly because I am sending a 21 integer list to Arduino. I am curious on how I would have predefined colors in Arudino and how to go about implementing that?
oh! Thank you so much! I was able to rearrange the Max patch pretty easily except the Aruduino code won't compile bc I keep getting the error:no known conversion for argument 2 from 'String' to 'uint32_t {aka long unsigned int}'
I tried a couple things but I am not quite sure how to make the conversion work
Unfortunately not. It gets the colors to display and the shut off values are outputting properly but the LEDs are staying lit. It seems to be an Arduino problem more than a Max problem, but now I am just stumped at this point.
Can You make it work with a single note on - note off ?
You could try to delete line
if (Serial.read() == '\n') {
and take one } at the end away
Otherwise You could try to switch to fast Led lib
Holy crap, I know what the problem is:
ints higher than 100 have no address, so we have to set Off notes
to LED addresses again - subtract 100.
I'll make new arduino sketch and post it soon
It works!!! There is still good amount of lag but the strips aren't glitching out anymore so I am very happy. Thank you so much!! I was able to simplify the note-offs into only one if statement. I am also going to try and figure out a way to simplify the note-ons as well in hopes of decreasing the lag. Here my patch so far. It changed a lot. Currently, it reads in midi data and outputs the note-on and note-off which is then sent to the Arduino.
deleted post
Now good that it at least works,
fighting the lag would mean digging deeper
into serial input - LED exec relationship, trying fastLED lib or even
PRJC octows2811 , or at the end using faster arduino, like teensy or due.
All this if statements do not matter much in terms of execution.
If one number is matched than strip.show gets executed , otherwise not.
all the lines with if statements for note on and note offs
were generated in max as sprintf string directly from the rgb coll
and than pasted in the sketch.
If You would keep all note off statements, than You could even
set different colors for released notes ....