loop на паузу с ИК пульта
- Войдите на сайт для отправки комментариев
Ср, 23/11/2016 - 01:26
Программа вуализатор для ленты ws2812b. Взято тут: https://github.com/bartlettmic/SparkFun-RGB-LED-Music-Sound-Visualizer-Arduino-Code
Прикрутил к ней управление по ИК с пульта ТВ. Первоначально ИК управление работает (выбор статической подсветки, выключение подсветки) но полсле старта вуализатора перестает реагировать на ИК команды.
Суть вопроса. Как достучаться до сего чуда?
//SparkFun Addressable RGB LED Sound and Music Visualizer Tutorial Arduino Code by Michael Bartlett //Libraries #include <Adafruit_NeoPixel.h> //Library to simplify interacting with the LED strand #include <IRremote.h> // библиотека для ИК #ifdef __AVR__ #include <avr/power.h> //Includes the library for power reduction registers if your chip supports them. #endif //More info: http://www.nongnu.org/avr-libc/user-manual/group__avr__power.htlm //Constants (change these as necessary) #define LED_PIN A5 //Pin for the pixel strand. Can be analog or digital. #define LED_TOTAL 30 //Change this to the number of LEDs in your strand. #define LED_HALF LED_TOTAL/2 #define VISUALS 6 //Change this accordingly if you add/remove a visual in the switch-case in Visualize() #define BRIGHTNESS 64 #define Delay_T 200 #define AUDIO_PIN A0 //Pin for the envelope of the sound detector /* #define BUTTON_1 6 //Button 1 cycles color palettes #define BUTTON_2 5 //Button 2 cycles visualization modes #define BUTTON_3 4 //Button 3 toggles shuffle mode (automated changing of color and visual) */ int RECV_PIN = 3; // pin ИК приемника IRrecv irrecv(RECV_PIN); // создаем объект получения сигнала с заданного порта decode_results results; // переменная хранящая результат int LED = 13; // для теста //////////<Globals> // These values either need to be remembered from the last pass of loop() or // need to be accessed by several functions in one pass, so they need to be global. Adafruit_NeoPixel strand = Adafruit_NeoPixel(LED_TOTAL, LED_PIN, NEO_GRB + NEO_KHZ800); //LED strand objetcs uint16_t gradient = 0; //Used to iterate and loop through each color palette gradually //IMPORTANT: // This array holds the "threshold" of each color function (i.e. the largest number they take before repeating). // The values are in the same order as in ColorPalette()'s switch case (Rainbow() is first, etc). This is simply to // keep "gradient" from overflowing, the color functions themselves can take any positive value. For example, the // largest value Rainbow() takes before looping is 1529, so "gradient" should reset after 1529, as listed. // Make sure you add/remove values accordingly if you add/remove a color function in the switch-case in ColorPalette(). uint16_t thresholds[] = {1529, 1019, 764, 764, 764, 1274}; uint8_t palette = 0; //Holds the current color palette. uint8_t visual = 0; //Holds the current visual being displayed. uint8_t volume = 0; //Holds the volume level read from the sound detector. uint8_t last = 0; //Holds the value of volume from the previous loop() pass. float maxVol = 15; //Holds the largest volume recorded thus far to proportionally adjust the visual's responsiveness. float avgBump = 0; //Holds the "average" volume-change to trigger a "bump." float avgVol = 0; //Holds the "average" volume-level to proportionally adjust the visual experience. float shuffleTime = 0; //Holds how many seconds of runtime ago the last shuffle was (if shuffle mode is on). //////////////////////////////////////////////////////////////////////////////////////////////////////////////// //NOTE: The reason "average" is quoted is because it is not a true mathematical average. This is because I have // found what I call a "sequenced average" is more successful in execution than a real average. The difference // is that the sequenced average doesn't use the pool of all values recorded thus far, but rather averages the // last average and the current value received (in sequence). Concretely: // // True average: (1 + 2 + 3) / 3 = 2 // Sequenced: (1 + 2) / 2 = 1.5 --> (1.5 + 3) / 2 = 2.25 (if 1, 2, 3 was the order the values were received) // // All "averages" in the program operate this way. The difference is subtle, but the reason is that sequenced // averages are more adaptive to changes in the overall volume. In other words, if you went from loud to quiet, // the sequenced average is more likely to show an accurate and proportional adjustment more fluently. //////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool shuffle = true; //Toggles shuffle mode. bool bump = false; //Used to pass if there was a "bump" in volume //For Traffic() visual int8_t pos[LED_TOTAL] = { -2}; //Stores a population of color "dots" to iterate across the LED strand. uint8_t rgb[LED_TOTAL][3] = {0}; //Stores each dot's specific RGB values. //For Snake() visual bool left = false; //Determines the direction of iteration. Recycled in PaletteDance() int8_t dotPos = 0; //Holds which LED in the strand the dot is positioned at. Recycled in most other visuals. float timeBump = 0; //Holds the time (in runtime seconds) the last "bump" occurred. float avgTime = 0; //Holds the "average" amount of time between each "bump" (used for pacing the dot's movement). char flg=0; //////////</Globals> //////////<Standard Functions> void setup() { //Like it's named, this gets ran before any other function. irrecv.enableIRIn(); // включаем ИК-приемник digitalWrite(LED, LOW); //test светодиод на ноге 13 не светит на плей и светит на стоп // Serial.begin(9600); //Sets data rate for serial data transmission. /* //Defines the buttons pins to be input. pinMode(BUTTON_1, INPUT); pinMode(BUTTON_2, INPUT); pinMode(BUTTON_3, INPUT); //Write a "HIGH" value to the button pins. digitalWrite(BUTTON_1, HIGH); digitalWrite(BUTTON_2, HIGH); digitalWrite(BUTTON_3, HIGH); */ strand.setBrightness(BRIGHTNESS); strand.begin(); //Initialize the LED strand object. strand.show(); //Show a blank strand, just to get the LED's ready for use. } void loop(){ IRremote(); //This is where the magic happens. This loop produces each frame of the visual. volume = analogRead(AUDIO_PIN); //Record the volume level from the sound detector //Sets a threshold for volume. // In practice I've found noise can get up to 15, so if it's lower, the visual thinks it's silent. // Also if the volume is less than average volume / 2 (essentially an average with 0), it's considered silent. if (volume < avgVol / 2.0 || volume < 15) volume = 0; else avgVol = (avgVol + volume) / 2.0; //If non-zeo, take an "average" of volumes. //If the current volume is larger than the loudest value recorded, overwrite if (volume > maxVol) maxVol = volume; //Check the Cycle* functions for specific instructions if you didn't include buttons in your design. //////////////////////////////////////////////////////////////////////////////////////////////////// CyclePalette(); //Changes palette for shuffle mode or button press. CycleVisual(); //Changes visualization for shuffle mode or button press. // ToggleShuffle(); //Toggles shuffle mode. Delete this if you didn't use buttons. //////////////////////////////////////////////////////////////////////////////////////////////////// //This is where "gradient" is modulated to prevent overflow. if (gradient > thresholds[palette]) { gradient %= thresholds[palette] + 1; //Everytime a palette gets completed is a good time to readjust "maxVol," just in case // the song gets quieter; we also don't want to lose brightness intensity permanently // because of one stray loud sound. maxVol = (maxVol + volume) / 2.0; } //If there is a decent change in volume since the last pass, average it into "avgBump" if (volume - last > 10) avgBump = (avgBump + (volume - last)) / 2.0; //If there is a notable change in volume, trigger a "bump" // avgbump is lowered just a little for comparing to make the visual slightly more sensitive to a beat. bump = (volume - last > avgBump * .9); //If a "bump" is triggered, average the time between bumps if (bump) { avgTime = (((millis() / 1000.0) - timeBump) + avgTime) / 2.0; timeBump = millis() / 1000.0; } if (flg==1){ digitalWrite(LED, LOW); Visualize(); //Calls the appropriate visualization to be displayed with the globals as they are. } gradient++; //Increments gradient last = volume; //Records current volume for next pass delay(30); //Paces visuals so they aren't too fast to be enjoyable } //////////</Standard Functions> /////////</IRremote void IRremote() { if (irrecv.decode(&results)) { // если есть сигнал if (results.value == 0x20DF8D72) { for (int i = 0; i < LED_TOTAL; i++) strand.setPixelColor(i, strand.Color(0, 0, 0)); // 00000 Black (stop) strand.show(); flg=0; digitalWrite(LED, HIGH); delay (Delay_T); } if (results.value == 0x20DFC639) { for (int i = 0; i < LED_TOTAL; i++) strand.setPixelColor(i, strand.Color(255, 255, 255)); // White strand.show(); delay (Delay_T); } if (results.value == 0x20DF8679) { for (int i = 0; i < LED_TOTAL; i++) strand.setPixelColor(i, strand.Color(0, 0, 255)); // blue strand.show(); delay (Delay_T); } if (results.value == 0x20DF8E71) { for (int i = 0; i < LED_TOTAL; i++) strand.setPixelColor(i, strand.Color(0, 255, 0)); // RED strand.show(); delay (Delay_T); } if (results.value == 0x20DF4EB1) { for (int i = 0; i < LED_TOTAL; i++) strand.setPixelColor(i, strand.Color(255, 0, 0)); // Green strand.show(); delay (Delay_T); } if (results.value == 0x20DFBD42) { strand.setBrightness((BRIGHTNESS)+30); // +++++ strand.show(); delay (Delay_T); } if (results.value == 0x20DF718E) { strand.setBrightness((BRIGHTNESS)); // midle BRIGHTNESS strand.show(); delay (Delay_T); } if (results.value == 0x20DFF10E) { strand.setBrightness((BRIGHTNESS)-30); // ----- strand.show(); delay (Delay_T); } if (results.value == 0x20DF0DF2) { // PLAY Visualize flg=1; delay (Delay_T); } irrecv.resume(); // получаем следующее значение } } //////////<Visual Functions> //This function calls the appropriate visualization based on the value of "visual" void Visualize() { switch (visual) { case 0: return Pulse(); case 1: return PalettePulse(); case 2: return Traffic(); case 3: return Snake(); case 4: return PaletteDance(); case 5: return Glitter(); case 6: return Paintball(); default: return Pulse(); } } ////////////////////////////////////////////////////////////////////////////////////////////////////////// //NOTE: The strand displays RGB values as a 32 bit unsigned integer (uint32_t), which is why ColorPalette() // and all associated color functions' return types are uint32_t. This value is a composite of 3 // unsigned 8bit integer (uint8_t) values (0-255 for each of red, blue, and green). You'll notice the // function split() (listed below) is used to dissect these 8bit values from the 32-bit color value. ////////////////////////////////////////////////////////////////////////////////////////////////////////// //This function calls the appropriate color palette based on "palette" // If a negative value is passed, returns the appropriate palette withe "gradient" passed. // Otherwise returns the color palette with the passed value (useful for fitting a whole palette on the strand). uint32_t ColorPalette(float num) { switch (palette) { case 0: return (num < 0) ? Rainbow(gradient) : Rainbow(num); case 1: return (num < 0) ? Sunset(gradient) : Sunset(num); case 2: return (num < 0) ? Ocean(gradient) : Ocean(num); case 3: return (num < 0) ? PinaColada(gradient) : PinaColada(num); case 4: return (num < 0) ? Sulfur(gradient) : Sulfur(num); case 5: return (num < 0) ? NoGreen(gradient) : NoGreen(num); default: return Rainbow(gradient); } } /////////////////////////////////////////////////////////////////////////////////////////////////////////////// //NOTE: All of these visualizations feature some aspect that affects brightness based on the volume relative to // maxVol, so that louder = brighter. Initially, I did simple proportions (volume/maxvol), but I found this // to be visually indistinct. I then tried an exponential method (raising the value to the power of // volume/maxvol). While this was more visually satisfying, I've opted for a balance between the two. You'll // notice something like pow(volume/maxVol, 2.0) in the functions below. This simply squares the ratio of // volume to maxVol to get a more exponential curve, but not as exaggerated as an actual exponential curve. // In essence, this makes louder volumes brighter, and lower volumes dimmer, to be more visually distinct. /////////////////////////////////////////////////////////////////////////////////////////////////////////////// //PULSE //Pulse from center of the strand void Pulse() { fade(0.75); //Listed below, this function simply dims the colors a little bit each pass of loop() //Advances the palette to the next noticeable color if there is a "bump" if (bump) gradient += thresholds[palette] / 24; //If it's silent, we want the fade effect to take over, hence this if-statement if (volume > 0) { uint32_t col = ColorPalette(-1); //Our retrieved 32-bit color //These variables determine where to start and end the pulse since it starts from the middle of the strand. // The quantities are stored in variables so they only have to be computed once (plus we use them in the loop). int start = LED_HALF - (LED_HALF * (volume / maxVol)); int finish = LED_HALF + (LED_HALF * (volume / maxVol)) + strand.numPixels() % 2; //Listed above, LED_HALF is simply half the number of LEDs on your strand. ↑ this part adjusts for an odd quantity. for (int i = start; i < finish; i++) { //"damp" creates the fade effect of being dimmer the farther the pixel is from the center of the strand. // It returns a value between 0 and 1 that peaks at 1 at the center of the strand and 0 at the ends. float damp = sin((i - start) * PI / float(finish - start)); //Squaring damp creates more distinctive brightness. damp = pow(damp, 2.0); //Fetch the color at the current pixel so we can see if it's dim enough to overwrite. uint32_t col2 = strand.getPixelColor(i); //Takes advantage of one for loop to do the following: // Appropriatley adjust the brightness of this pixel using location, volume // Take the average RGB value of the intended color and the existing color, for comparison uint8_t colors[3]; float avgCol = 0, avgCol2 = 0; for (int k = 0; k < 3; k++) { colors[k] = split(col, k) * damp * pow(volume / maxVol, 2); avgCol += colors[k]; avgCol2 += split(col2, k); } avgCol /= 3.0, avgCol2 /= 3.0; //Compare the average colors as "brightness". Only overwrite dim colors so the fade effect is more apparent. if (avgCol > avgCol2) strand.setPixelColor(i, strand.Color(colors[0], colors[1], colors[2])); } } //This command actually shows the lights. If you make a new visualization, don't forget this! strand.show(); } //PALETTEPULSE //Same as Pulse(), but colored the entire pallet instead of one solid color void PalettePulse() { fade(0.75); if (bump) gradient += thresholds[palette] / 24; if (volume > 0) { int start = LED_HALF - (LED_HALF * (volume / maxVol)); int finish = LED_HALF + (LED_HALF * (volume / maxVol)) + strand.numPixels() % 2; for (int i = start; i < finish; i++) { float damp = sin((i - start) * PI / float(finish - start)); damp = pow(damp, 2.0); //This is the only difference from Pulse(). The color for each pixel isn't the same, but rather the // entire gradient fitted to the spread of the pulse, with some shifting from "gradient". int val = thresholds[palette] * (i - start) / (finish - start); val += gradient; uint32_t col = ColorPalette(val); uint32_t col2 = strand.getPixelColor(i); uint8_t colors[3]; float avgCol = 0, avgCol2 = 0; for (int k = 0; k < 3; k++) { colors[k] = split(col, k) * damp * pow(volume / maxVol, 2); avgCol += colors[k]; avgCol2 += split(col2, k); } avgCol /= 3.0, avgCol2 /= 3.0; if (avgCol > avgCol2) strand.setPixelColor(i, strand.Color(colors[0], colors[1], colors[2])); } } strand.show(); } //TRAFFIC //Dots racing into each other void Traffic() { //fade() actually creates the trail behind each dot here, so it's important to include. fade(0.8); //Create a dot to be displayed if a bump is detected. if (bump) { //This mess simply checks if there is an open position (-2) in the pos[] array. int8_t slot = 0; for (slot; slot < sizeof(pos); slot++) { if (pos[slot] < -1) break; else if (slot + 1 >= sizeof(pos)) { slot = -3; break; } } //If there is an open slot, set it to an initial position on the strand. if (slot != -3) { //Evens go right, odds go left, so evens start at 0, odds at the largest position. pos[slot] = (slot % 2 == 0) ? -1 : strand.numPixels(); //Give it a color based on the value of "gradient" during its birth. uint32_t col = ColorPalette(-1); gradient += thresholds[palette] / 24; for (int j = 0; j < 3; j++) { rgb[slot][j] = split(col, j); } } } //Again, if it's silent we want the colors to fade out. if (volume > 0) { //If there's sound, iterate each dot appropriately along the strand. for (int i = 0; i < sizeof(pos); i++) { //If a dot is -2, that means it's an open slot for another dot to take over eventually. if (pos[i] < -1) continue; //As above, evens go right (+1) and odds go left (-1) pos[i] += (i % 2) ? -1 : 1; //Odds will reach -2 by subtraction, but if an even dot goes beyond the LED strip, it'll be purged. if (pos[i] >= strand.numPixels()) pos[i] = -2; //Set the dot to its new position and respective color. // I's old position's color will gradually fade out due to fade(), leaving a trail behind it. strand.setPixelColor( pos[i], strand.Color( float(rgb[i][0]) * pow(volume / maxVol, 2.0), float(rgb[i][1]) * pow(volume / maxVol, 2.0), float(rgb[i][2]) * pow(volume / maxVol, 2.0)) ); } } strand.show(); //Again, don't forget to actually show the lights! } //SNAKE //Dot sweeping back and forth to the beat void Snake() { if (bump) { //Change color a little on a bump gradient += thresholds[palette] / 30; //Change the direction the dot is going to create the illusion of "dancing." left = !left; } fade(0.975); //Leave a trail behind the dot. uint32_t col = ColorPalette(-1); //Get the color at current "gradient." //The dot should only be moved if there's sound happening. // Otherwise if noise starts and it's been moving, it'll appear to teleport. if (volume > 0) { //Sets the dot to appropriate color and intensity strand.setPixelColor(dotPos, strand.Color( float(split(col, 0)) * pow(volume / maxVol, 1.5), float(split(col, 1)) * pow(volume / maxVol, 1.5), float(split(col, 2)) * pow(volume / maxVol, 1.5)) ); //This is where "avgTime" comes into play. // That variable is the "average" amount of time between each "bump" detected. // So we can use that to determine how quickly the dot should move so it matches the tempo of the music. // The dot moving at normal loop speed is pretty quick, so it's the max speed if avgTime < 0.15 seconds. // Slowing it down causes the color to update, but only change position every other amount of loops. if (avgTime < 0.15) dotPos += (left) ? -1 : 1; else if (avgTime >= 0.15 && avgTime < 0.5 && gradient % 2 == 0) dotPos += (left) ? -1 : 1; else if (avgTime >= 0.5 && avgTime < 1.0 && gradient % 3 == 0) dotPos += (left) ? -1 : 1; else if (gradient % 4 == 0) dotPos += (left) ? -1 : 1; } strand.show(); // Display the lights //Check if dot position is out of bounds. if (dotPos < 0) dotPos = strand.numPixels() - 1; else if (dotPos >= strand.numPixels()) dotPos = 0; } //PALETTEDANCE //Projects a whole palette which oscillates to the beat, similar to the snake but a whole gradient instead of a dot void PaletteDance() { //This is the most calculation-intensive visual, which is why it doesn't need delayed. if (bump) left = !left; //Change direction of iteration on bump //Only show if there's sound. if (volume > avgVol) { //This next part is convoluted, here's a summary of what's happening: // First, a sin wave function is introduced to change the brightness of all the pixels (stored in "sinVal") // This is to make the dancing effect more obvious. The trick is to shift the sin wave with the color so it all appears // to be the same object, one "hump" of color. "dotPos" is added here to achieve this effect. // Second, the entire current palette is proportionally fitted to the length of the LED strand (stored in "val" each pixel). // This is done by multiplying the ratio of position and the total amount of LEDs to the palette's threshold. // Third, the palette is then "shifted" (what color is displayed where) by adding "dotPos." // "dotPos" is added to the position before dividing, so it's a mathematical shift. However, "dotPos"'s range is not // the same as the range of position values, so the function map() is used. It's basically a built in proportion adjuster. // Lastly, it's all multiplied together to get the right color, and intensity, in the correct spot. // "gradient" is also added to slowly shift the colors over time. for (int i = 0; i < strand.numPixels(); i++) { float sinVal = abs(sin( (i + dotPos) * (PI / float(strand.numPixels() / 1.25) ) )); sinVal *= sinVal; sinVal *= volume / maxVol; unsigned int val = float(thresholds[palette] + 1) //map takes a value between -LED_TOTAL and +LED_TOTAL and returns one between 0 and LED_TOTAL * (float(i + map(dotPos, -1 * (strand.numPixels() - 1), strand.numPixels() - 1, 0, strand.numPixels() - 1)) / float(strand.numPixels())) + (gradient); val %= thresholds[palette]; //make sure "val" is within range of the palette uint32_t col = ColorPalette(val); //get the color at "val" strand.setPixelColor(i, strand.Color( float(split(col, 0))*sinVal, float(split(col, 1))*sinVal, float(split(col, 2))*sinVal) ); } //After all that, appropriately reposition "dotPos." dotPos += (left) ? -1 : 1; } //If there's no sound, fade. else fade(0.8); strand.show(); //Show lights. //Loop "dotPos" if it goes out of bounds. if (dotPos < 0) dotPos = strand.numPixels() - strand.numPixels() / 6; else if (dotPos >= strand.numPixels() - strand.numPixels() / 6) dotPos = 0; } //GLITTER //Creates white sparkles on a color palette to the beat void Glitter() { //This visual also fits a whole palette on the entire strip // This just makes the palette cycle more quickly so it's more visually pleasing gradient += thresholds[palette] / 204; //"val" is used again as the proportional value to pass to ColorPalette() to fit the whole palette. for (int i = 0; i < strand.numPixels(); i++) { unsigned int val = float(thresholds[palette] + 1) * (float(i) / float(strand.numPixels())) + (gradient); val %= thresholds[palette]; uint32_t col = ColorPalette(val); //We want the sparkles to be obvious, so we dim the background color. strand.setPixelColor(i, strand.Color( split(col, 0) / 6.0, split(col, 1) / 6.0, split(col, 2) / 6.0)); } //Create sparkles every bump if (bump) { //Random generator needs a seed, and micros() gives a large range of values. // micros() is the amount of microseconds since the program started running. randomSeed(micros()); //Pick a random spot on the strand. dotPos = random(strand.numPixels() - 1); //Draw sparkle at the random position, with appropriate brightness. strand.setPixelColor(dotPos, strand.Color( 255.0 * pow(volume / maxVol, 2.0), 255.0 * pow(volume / maxVol, 2.0), 255.0 * pow(volume / maxVol, 2.0))); } bleed(dotPos); strand.show(); //Show the lights. } //PAINTBALL //Recycles Glitter()'s random positioning; simulates "paintballs" of // color splattering randomly on the strand and bleeding together. void Paintball() { //If it's been twice the average time for a "bump" since the last "bump," start fading. if ((millis() / 1000.0) - timeBump > avgTime * 2.0) fade(0.99); //Bleeds colors together. Operates similarly to fade. For more info, see its definition below bleed(dotPos); //Create a new paintball if there's a bump (like the sparkles in Glitter()) if (bump) { //Random generator needs a seed, and micros() gives a large range of values. // micros() is the amount of microseconds since the program started running. randomSeed(micros()); //Pick a random spot on the strip. Random was already reseeded above, so no real need to do it again. dotPos = random(strand.numPixels() - 1); //Grab a random color from our palette. uint32_t col = ColorPalette(random(thresholds[palette])); //Array to hold final RGB values uint8_t colors[3]; //Relates brightness of the color to the relative volume and potentiometer value. for (int i = 0; i < 3; i++) colors[i] = split(col, i) * pow(volume / maxVol, 2.0); //Splatters the "paintball" on the random position. strand.setPixelColor(dotPos, strand.Color(colors[0], colors[1], colors[2])); //This next part places a less bright version of the same color next to the left and right of the // original position, so that the bleed effect is stronger and the colors are more vibrant. for (int i = 0; i < 3; i++) colors[i] *= .8; strand.setPixelColor(dotPos - 1, strand.Color(colors[0], colors[1], colors[2])); strand.setPixelColor(dotPos + 1, strand.Color(colors[0], colors[1], colors[2])); } strand.show(); //Show lights. } ///////////////////////////////////////////////////////////////////////////////////////////////////// //DEBUG CYCLE //No reaction to sound, merely to see gradient progression of color palettes //NOT implemented in code as is, but is easily includable in the switch-case. void Cycle() { for (int i = 0; i < strand.numPixels(); i++) { float val = float(thresholds[palette]) * (float(i) / float(strand.numPixels())) + (gradient); val = int(val) % thresholds[palette]; strand.setPixelColor(i, ColorPalette(val)); } strand.show(); gradient += 32; } ///////////////////////////////////////////////////////////////////////////////////////////////////// //////////</Visual Functions> //////////<Helper Functions> void CyclePalette() { //IMPORTANT: Delete this whole if-block if you didn't use buttons////////////////////////////////// /* /If a button is pushed, it sends a "false" reading if (!digitalRead(BUTTON_1)) { palette++; //This is this button's purpose, to change the color palette. //If palette is larger than the population of thresholds[], start back at 0 // This is why it's important you add a threshold to the array if you add a // palette, or the program will cylce back to Rainbow() before reaching it. if (palette >= sizeof(thresholds) / 2) palette = 0; gradient %= thresholds[palette]; //Modulate gradient to prevent any overflow that may occur. //The button is close to the microphone on my setup, so the sound of pushing it is // relatively loud to the sound detector. This causes the visual to think a loud noise // happened, so the delay simply allows the sound of the button to pass unabated. delay(350); maxVol = avgVol; //Set max volume to average for a fresh experience. } */////////////////////////////////////////////////////////////////////////////////////////////////// //If shuffle mode is on, and it's been 30 seconds since the last shuffle, and then a modulo // of gradient to get a random decision between palette or visualization shuffle if (shuffle && millis() / 1000.0 - shuffleTime > 30 && gradient % 2) { shuffleTime = millis() / 1000.0; //Record the time this shuffle happened. palette++; if (palette >= sizeof(thresholds) / 2) palette = 0; gradient %= thresholds[palette]; maxVol = avgVol; //Set the max volume to average for a fresh experience. } } void CycleVisual() { /* /IMPORTANT: Delete this whole if-block if you didn't use buttons////////////////////////////////// if (!digitalRead(BUTTON_2)) { visual++; //The purpose of this button: change the visual mode gradient = 0; //Prevent overflow //Resets "visual" if there are no more visuals to cycle through. if (visual > VISUALS) visual = 0; //This is why you should change "VISUALS" if you add a visual, or the program loop over it. //Resets the positions of all dots to nonexistent (-2) if you cycle to the Traffic() visual. if (visual == 1) memset(pos, -2, sizeof(pos)); //Gives Snake() and PaletteDance() visuals a random starting point if cycled to. if (visual == 2 || visual == 3) { randomSeed(analogRead(0)); dotPos = random(strand.numPixels()); } //Like before, this delay is to prevent a button press from affecting "maxVol." delay(350); maxVol = avgVol; //Set max volume to average for a fresh experience } */ ////////////////////////////////////////////////////////////////////////////////////////////////// //If shuffle mode is on, and it's been 30 seconds since the last shuffle, and then a modulo // of gradient WITH INVERTED LOGIC to get a random decision between what to shuffle. // This guarantees one and only one of these shuffles will occur. if (shuffle && millis() / 1000.0 - shuffleTime > 30 && !(gradient % 2)) { shuffleTime = millis() / 1000.0; //Record the time this shuffle happened. visual++; gradient = 0; if (visual > VISUALS) visual = 0; if (visual == 1) memset(pos, -2, sizeof(pos)); if (visual == 2 || visual == 3) { randomSeed(analogRead(0)); dotPos = random(strand.numPixels()); } maxVol = avgVol; } } /* /IMPORTANT: Delete this function if you didn't use buttons.///////////////////////////////////////// void ToggleShuffle() { if (!digitalRead(BUTTON_3)) { shuffle = !shuffle; //This button's purpose: toggle shuffle mode. //This delay is to prevent the button from taking another reading while you're pressing it delay(500); //Reset these things for a fresh experience. maxVol = avgVol; avgBump = 0; } } */ ///////////////////////////////////////////////////////////////////////////////////////////////////// //Fades lights by multiplying them by a value between 0 and 1 each pass of loop(). void fade(float damper) { //"damper" must be between 0 and 1, or else you'll end up brightening the lights or doing nothing. for (int i = 0; i < strand.numPixels(); i++) { //Retrieve the color at the current position. uint32_t col = strand.getPixelColor(i); //If it's black, you can't fade that any further. if (col == 0) continue; float colors[3]; //Array of the three RGB values //Multiply each value by "damper" for (int j = 0; j < 3; j++) colors[j] = split(col, j) * damper; //Set the dampened colors back to their spot. strand.setPixelColor(i, strand.Color(colors[0] , colors[1], colors[2])); } } //"Bleeds" colors currently in the strand by averaging from a designated "Point" void bleed(uint8_t Point) { for (int i = 1; i < strand.numPixels(); i++) { //Starts by look at the pixels left and right of "Point" // then slowly works its way out int sides[] = {Point - i, Point + i}; for (int i = 0; i < 2; i++) { //For each of Point+i and Point-i, the pixels to the left and right, plus themselves, are averaged together. // Basically, it's setting one pixel to the average of it and its neighbors, starting on the left and right // of the starting "Point," and moves to the ends of the strand int point = sides[i]; uint32_t colors[] = {strand.getPixelColor(point - 1), strand.getPixelColor(point), strand.getPixelColor(point + 1) }; //Sets the new average values to just the central point, not the left and right points. strand.setPixelColor(point, strand.Color( float( split(colors[0], 0) + split(colors[1], 0) + split(colors[2], 0) ) / 3.0, float( split(colors[0], 1) + split(colors[1], 1) + split(colors[2], 1) ) / 3.0, float( split(colors[0], 2) + split(colors[1], 2) + split(colors[2], 2) ) / 3.0) ); } } } //As mentioned above, split() gives you one 8-bit color value //from the composite 32-bit value that the NeoPixel deals with. //This is accomplished with the right bit shift operator, ">>" uint8_t split(uint32_t color, uint8_t i ) { //0 = Red, 1 = Green, 2 = Blue if (i == 0) return color >> 16; if (i == 1) return color >> 8; if (i == 2) return color >> 0; return -1; } //////////</Helper Functions> //////////<Palette Functions> //These functions simply take a value and return a gradient color // in the form of an unsigned 32-bit integer //The gradients return a different, changing color for each multiple of 255 // This is because the max value of any of the 3 RGB values is 255, so it's // an intuitive cutoff for the next color to start appearing. // Gradients should also loop back to their starting color so there's no jumps in color. uint32_t Rainbow(unsigned int i) { if (i > 1529) return Rainbow(i % 1530); if (i > 1274) return strand.Color(255, 0, 255 - (i % 255)); //violet -> red if (i > 1019) return strand.Color((i % 255), 0, 255); //blue -> violet if (i > 764) return strand.Color(0, 255 - (i % 255), 255); //aqua -> blue if (i > 509) return strand.Color(0, 255, (i % 255)); //green -> aqua if (i > 255) return strand.Color(255 - (i % 255), 255, 0); //yellow -> green return strand.Color(255, i, 0); //red -> yellow } uint32_t Sunset(unsigned int i) { if (i > 1019) return Sunset(i % 1020); if (i > 764) return strand.Color((i % 255), 0, 255 - (i % 255)); //blue -> red if (i > 509) return strand.Color(255 - (i % 255), 0, 255); //purple -> blue if (i > 255) return strand.Color(255, 128 - (i % 255) / 2, (i % 255)); //orange -> purple return strand.Color(255, i / 2, 0); //red -> orange } uint32_t Ocean(unsigned int i) { if (i > 764) return Ocean(i % 765); if (i > 509) return strand.Color(0, i % 255, 255 - (i % 255)); //blue -> green if (i > 255) return strand.Color(0, 255 - (i % 255), 255); //aqua -> blue return strand.Color(0, 255, i); //green -> aqua } uint32_t PinaColada(unsigned int i) { if (i > 764) return PinaColada(i % 765); if (i > 509) return strand.Color(255 - (i % 255) / 2, (i % 255) / 2, (i % 255) / 2); //red -> half white if (i > 255) return strand.Color(255, 255 - (i % 255), 0); //yellow -> red return strand.Color(128 + (i / 2), 128 + (i / 2), 128 - i / 2); //half white -> yellow } uint32_t Sulfur(unsigned int i) { if (i > 764) return Sulfur(i % 765); if (i > 509) return strand.Color(i % 255, 255, 255 - (i % 255)); //aqua -> yellow if (i > 255) return strand.Color(0, 255, i % 255); //green -> aqua return strand.Color(255 - i, 255, 0); //yellow -> green } uint32_t NoGreen(unsigned int i) { if (i > 1274) return NoGreen(i % 1275); if (i > 1019) return strand.Color(255, 0, 255 - (i % 255)); //violet -> red if (i > 764) return strand.Color((i % 255), 0, 255); //blue -> violet if (i > 509) return strand.Color(0, 255 - (i % 255), 255); //aqua -> blue if (i > 255) return strand.Color(255 - (i % 255), 255, i % 255); //yellow -> aqua return strand.Color(255, i, 0); //red -> yellow } //NOTE: This is an example of a non-gradient palette: you will get straight red, white, or blue // This works fine, but there is no gradient effect, this was merely included as an example. // If you wish to include it, put it in the switch-case in ColorPalette() and add its // threshold (764) to thresholds[] at the top. uint32_t USA(unsigned int i) { if (i > 764) return USA(i % 765); if (i > 509) return strand.Color(0, 0, 255); //blue if (i > 255) return strand.Color(128, 128, 128); //white return strand.Color(255, 0, 0); //red } //////////</Palette Functions>
Скетч зачетный, как раз искал нечто подобное, буду внткать и перепиливать... жаль под рукой нет микрофона. По вашей проблеме нужно чтение порта ir впендюхать почаще, только это может затормозить эффекты
тут как бы не совсем микрофон.
http://cdn.sparkfun.com/datasheets/Sensors/Sound/sound-detector.pdf
Проблему решить не удалось? Там в скетче есть delay(30) предлагаю вместо него запилить ожидание сигнала на 30 милисекунд, я так понял луп там не тормозит особо
Видел проект похожий, но там две ардуины, одна отвечает за пульт, другая за визуализацию: https://github.com/atuline/FastLED-Demos/tree/master/aalight/
Схема подключения смотрите в aalight.png
Мысль про 2 ардуины посещала. Ввиду осеньннего обострения лени )) пока будет работать по принципу - надоело, выключил