├── README.md ├── Tutorial ├── absolute │ └── absolute.ino ├── agcAvg │ └── agcAvg.ino ├── agcPI │ └── agcPI.ino ├── centering_1 │ └── centering_1.ino ├── centering_2 │ └── centering_2.ino ├── centering_3 │ └── centering_3.ino ├── centering_4 │ └── centering_4.ino ├── peak │ └── peak.ino └── squelch │ └── squelch.ino ├── agcAvg └── agcAvg.ino ├── agcAvg_Pal └── agcAvg_Pal.ino ├── agcPI └── agcPI.ino ├── agcPI_Pal └── agcPI_Pal.ino ├── fht_log_fast └── fht_log_fast.ino ├── fht_log_ripple └── fht_log_ripple.ino ├── notasound ├── besin.h ├── commands.h ├── fillnoise.h ├── fire.h ├── firewide.h ├── getsample.h ├── gradient_palettes.h ├── jugglep.h ├── matrix.h ├── myvumeter.h ├── noisewide.h ├── notasound.ino ├── onesine.h ├── pixelblend.h ├── pixels.h ├── plasma.h ├── plasma2.h ├── rainbowpeak.h ├── ripple.h ├── sinephase.h └── support.h ├── sound_bracelet └── sound_bracelet.ino ├── sound_noise └── sound_noise.ino ├── sound_pal └── sound_pal.ino ├── sound_ripple └── sound_ripple.ino ├── sound_sample └── sound_sample.ino └── sound_wave └── sound_wave.ino /README.md: -------------------------------------------------------------------------------- 1 | # FastLED-SoundReactive 2 | 3 | Sound Reactive displays for FastLED 4 | 5 | By: Andrew Tuline 6 | 7 | 8 | Here's some sound reactive demos for FastLED. Except for my original Open Music 9 | Labs FFT demo running on a Nano, they have been tested both with an Arduino Nano 10 | as well as an ESP8266 based WeMOS D1 Mini. Most importantly, my demos do NOT use 11 | delay statements as delays can cause havoc with polled inputs such as triggered 12 | buttons. 13 | 14 | These new demos use Automatic Gain Control, so that quiet sounds still get a reaction 15 | and continuous loud ones don't overdrive all the LED's. 16 | 17 | * One method uses direct Proportional control against an average. 18 | * The other uses a Proportional Integral control loop using a calculated average 19 | as feedback. 20 | 21 | Note: Not all the demos have been cutover to AGC. . I'll get there. 22 | 23 | 24 | Thanks to Ben Hencke of PixelBlaze fame for writing some PI sound code that I was 25 | able to learn from and eventually adapt to an Arduino. 26 | 27 | 28 | 29 | **Sound functionality** 30 | - Continuous sampling of sounds via ADMP401 microphone. 31 | - Auto offset centering. 32 | - Implement squelch of background noise. 33 | - Averaging of last 32 samples. 34 | - Ghetto peak detection. 35 | - Integration of sound with various display routines. 36 | - IR control capability. 37 | - No MSGEQ7 required for my FFT/FHT routines. 38 | - Using Open Music Labs FHT for Arduino Nano. 39 | - Using ArduinoFFT for ESP8266. 40 | 41 | 42 | ## My FastLED Animation Philosophy 43 | 44 | - Do NOT use delay statements in the loop as that breaks input routines (i.e. button). 45 | - Do not use nested loops (for performance reasons). 46 | - Use millis() as a real time counter unless a fixed counter is required. 47 | - Spend a bit more time using high school math (ie trigonometry), rather than just count pixels. 48 | - Keep the display routines as short as possible. 49 | - Data typing as strict as possible i.e. why define an int when a uint8_t is all that is required. Oh, and floats are not used at all. 50 | - Localize variables to each routine as much as possible. 51 | - Break out the display routines into separate .h files for increased readability and modularity. 52 | - Be generous with comments. 53 | 54 | 55 | ## Microphones 56 | 57 | If you go out and buy one of those cheap sound sensors from aliexpress, you will be sorely disappointed. The ADMP401 MEMS microphone includes an amplifier (with a gain of 67db), which provides a line in signal that's adequate for the Arduino works just fine. Those sound sensors don't. You have been warned. 58 | 59 | ## Files 60 | 61 | * getSample - Basic sound sampling with auto-centering. 62 | * agcAvg - Sampling with averaging AGC and CHSV output. 63 | * agcAvg_Pal - Sampling with averaging AGC and Palette output. 64 | * agcPI - Sampling with Proportional Controller AGC and CHSV output. 65 | * agcPI_Pal - Sampling with Proportional Controller AGC and Palette output. 66 | 67 | 68 | * sound_bracelet - More LED's with rising amplitude. Has a trailing LED. Hastily converted to use FastLED. 69 | * sound_noise - Perlin noise coming out from the center. 70 | * sound_pal - Sample at end is propagated to the other end. 71 | * sound_ripple - Sampled peaks generate ripples throughout. 72 | * sound_wave - Sample in middle is propagated out from the center. 73 | 74 | Not done yet: 75 | 76 | A LOT more sound reactive demos to come. Also, working on 'notasound', which is the big one. 77 | 78 | 79 | 80 | ##agcAvg and agcPI 81 | 82 | The purpose of agcAvg and agcPI routines is to ensure the LED's are not under or over driven at any volume level. 83 | In practice, I haven't used agcPI as the agcAvg version is simpler and seems to suffice. 84 | So much for the 2 months I spent getting agcPI running. 85 | 86 | 87 | 88 | ## More 89 | 90 | Information about the awesome FastLED Library is available from: [fastled.io](http://fastled.io/) 91 | 92 | Download FastLED from: [github.com/FastLED/FastLED](https://github.com/FastLED/FastLED) 93 | 94 | FastLED Documentation is at: [http://fastled.io/docs/3.1/modules.html](http://fastled.io/docs/3.1/modules.html) 95 | 96 | The FastLED community is at [https://www.reddit.com/r/fastled](https://www.reddit.com/r/fastled) 97 | 98 | 99 | ----------------------------------------------------------------------------------- 100 | 101 | * My Youtube channel is at: https://www.youtube.com/user/atuline/videos 102 | * My Github account is at: https://github.com/atuline 103 | * My Gists are at: https://gist.github.com/atuline 104 | * My Pastebins are at: https://pastebin.com/u/atuline 105 | * FastLED support forum: https://www.reddit.com/r/fastled 106 | -------------------------------------------------------------------------------- /Tutorial/absolute/absolute.ino: -------------------------------------------------------------------------------- 1 | /* take the absolute value of the centered data. 2 | * 3 | * By: Andrew Tuline 4 | * 5 | * Date: January 2020 6 | * 7 | * 8 | */ 9 | 10 | 11 | #define MIC_PIN 5 // Microphone 12 | 13 | float micLev; 14 | 15 | 16 | void setup() { 17 | Serial.begin(115200); 18 | analogReference(EXTERNAL); // Comment out this line for 3.3V Arduino's. 19 | delay(1000); 20 | } // setup() 21 | 22 | 23 | 24 | void loop() { 25 | getSample(); // Sample the sounds. 26 | } // loop() 27 | 28 | 29 | 30 | void getSample() { 31 | 32 | int16_t micIn; 33 | 34 | micIn = analogRead(MIC_PIN); // Sample the microphone. Range will result in 0 to 1023. 35 | micLev = ((micLev * 31) + micIn) / 32; // Smooth it out over the last 32 samples. 36 | 37 | micIn = micIn - micLev; 38 | micIn = abs(micIn); 39 | 40 | 41 | Serial.print(micIn); Serial.print(" "); 42 | Serial.print(0); Serial.print(" "); 43 | Serial.print(100); Serial.print(" "); 44 | Serial.println(" "); 45 | 46 | } // getSample() 47 | -------------------------------------------------------------------------------- /Tutorial/agcAvg/agcAvg.ino: -------------------------------------------------------------------------------- 1 | /* agcAvg 2 | * 3 | * By: Andrew Tuline 4 | * 5 | * Date: Jan, 2020 6 | * 7 | * An Automatic Gain Control for a microphone on an Arduino. 8 | * 9 | * This version uses simple averaging of 32 samples against a setpoint. Simple, but at least it works. 10 | * 11 | * It also includes a ghetto peak detection capability, which is displayed on led[0]. 12 | * 13 | */ 14 | 15 | 16 | #define MIC_PIN 5 // Analog port for microphone 17 | uint8_t squelch = 7; // Anything below this is background noise, so we'll make it '0'. 18 | int sample; // Current sample. 19 | float sampleAvg = 0; // Smoothed Average. 20 | float micLev = 0; // Used to convert returned value to have '0' as minimum. 21 | uint8_t maxVol = 11; // Reasonable value for constant volume for 'peak detector', as it won't always trigger. 22 | bool samplePeak = 0; // Boolean flag for peak. Responding routine must reset this flag. 23 | 24 | int sampleAgc, multAgc; 25 | uint8_t targetAgc = 60; // This is our setPoint at 20% of max for the adjusted output. 26 | 27 | 28 | 29 | void setup() { 30 | Serial.begin(115200); // Initialize serial port for debugging. 31 | analogReference(EXTERNAL); // Nano or other 5V AVR8 when using a 3.3V microphone. 32 | delay(1000); 33 | } // setup() 34 | 35 | 36 | 37 | void loop() { 38 | 39 | getSample(); // Sample the microphone. 40 | agcAvg(); // Calculated the PI adjusted value as sampleAvg. 41 | 42 | } // loop() 43 | 44 | 45 | 46 | void getSample() { 47 | 48 | int16_t micIn; // Current sample starts with negative values and large values, which is why it's 16 bit signed. 49 | static long peakTime; 50 | 51 | micIn = analogRead(MIC_PIN); // Poor man's analog Read. 52 | micLev = ((micLev * 31) + micIn) / 32; // Smooth it out over the last 32 samples for automatic centering. 53 | micIn -= micLev; // Let's center it to 0 now. 54 | micIn = abs(micIn); // And get the absolute value of each sample. 55 | sample = (micIn <= squelch) ? 0 : (sample + micIn) / 2; // Using a ternary operator, the resultant sample is either 0 or it's a bit smoothed out with the last sample. 56 | sampleAvg = ((sampleAvg * 31) + sample) / 32; // Smooth it out over the last 32 samples. 57 | 58 | if (sample > (sampleAvg+maxVol) && millis() > (peakTime + 50)) { // Poor man's beat detection by seeing if sample > Average + some value. 59 | samplePeak = 1; // Then we got a peak, else we don't. Display routines need to reset the samplepeak value in case they miss the trigger. 60 | peakTime=millis(); 61 | } 62 | 63 | } // getSample() 64 | 65 | 66 | 67 | void agcAvg() { // A simple averaging multiplier to automatically adjust sound sensitivity. 68 | 69 | multAgc = (sampleAvg < 1) ? targetAgc : targetAgc / sampleAvg; // Make the multiplier so that sampleAvg * multiplier = setpoint 70 | sampleAgc = sample * multAgc; 71 | if (sampleAgc > 255) sampleAgc = 255; 72 | 73 | //------------ Oscilloscope output --------------------------- 74 | // Serial.print(targetAgc); Serial.print(" "); 75 | // Serial.print(multAgc); Serial.print(" "); 76 | Serial.print(sampleAgc); Serial.print(" "); 77 | 78 | Serial.print(sample); Serial.print(" "); 79 | // Serial.print(sampleAvg); Serial.print(" "); 80 | // Serial.print(micLev); Serial.print(" "); 81 | // Serial.print(samplePeak); Serial.print(" "); samplePeak = 0; 82 | Serial.print(100); Serial.print(" "); 83 | Serial.print(0); Serial.print(" "); 84 | Serial.println(" "); 85 | 86 | } // agcAvg() 87 | -------------------------------------------------------------------------------- /Tutorial/agcPI/agcPI.ino: -------------------------------------------------------------------------------- 1 | /* agcPI 2 | * 3 | * By: Andrew Tuline 4 | * 5 | * Date: Jan, 2020 6 | * 7 | * An Automatic Gain Control for a microphone on an Arduino. 8 | * 9 | * This version uses a PI (proportional integral) control loop. 10 | * 11 | * See: https://en.wikipedia.org/wiki/PID_controller 12 | * 13 | * It also includes a ghetto peak detection capability, which is displayed on led[0]. 14 | * 15 | */ 16 | 17 | //#define FASTLED_ALLOW_INTERRUPTS 0 // Used for ESP8266. 18 | #include // FastLED library. 19 | 20 | #define MIC_PIN A5 // Nano or A0 on ESP8266 21 | uint8_t squelch = 7; // Anything below this is background noise, so we'll make it '0'. 22 | int sample; // Current sample. 23 | float sampleAvg = 0; // Can be used for smoothing signals. 24 | float micLev = 0; // Used to convert returned value to have '0' as minimum. 25 | uint8_t maxVol = 11; // Reasonable value for constant volume (above average) for 'peak detector'. 26 | bool samplePeak = 0; // Boolean flag for peak detected. Responding routine must reset this flag. 27 | 28 | uint8_t targetAgc = 60; // This is our setPoint at ~20% of max for the adjusted output. 29 | float kp = 2, ki = 4; // Proportional and Integral tuning constants. Kept as floating point in case we find better tuning. 30 | int err; // Current offset from our target. 31 | int minn = -20000, maxx = 20000; // Keep everything in check with these values. 32 | int samplePI; // Sensitivity is calculated by the PI routine. 33 | float samplePIAvg; // Calculated and stored average calculated sample is used for closed loop feedback. 34 | 35 | // Fixed definitions cannot change on the fly. 36 | #define LED_DT 12 // Data pin to connect to the strip. 37 | #define LED_CK 11 // Clock pin for WS2801 or APA102. 38 | #define COLOR_ORDER GRB // It's GRB for WS2812 and BGR for APA102. 39 | #define LED_TYPE WS2812 // Using APA102, WS2812, WS2801. Don't forget to modify LEDS.addLeds to suit. 40 | #define NUM_LEDS 30 // Number of LED's. 41 | 42 | uint8_t max_bright = 255; // Overall brightness. 43 | struct CRGB leds[NUM_LEDS]; // Initialize our LED array. 44 | 45 | 46 | 47 | void setup() { 48 | Serial.begin(115200); // Initialize serial port for debugging. 49 | delay(1000); 50 | analogReference(EXTERNAL); // Nano or other 5V AVR8 when using a 3.3V microphone. 51 | LEDS.addLeds(leds, NUM_LEDS); // Use this for WS2812 52 | FastLED.setBrightness(max_bright); 53 | FastLED.setMaxPowerInVoltsAndMilliamps(5, 500); // FastLED Power management set at 5V, 500mA 54 | } // setup() 55 | 56 | 57 | 58 | void loop() { 59 | 60 | EVERY_N_MILLIS(10) { 61 | fadeToBlackBy(leds, NUM_LEDS, 4); // 8 bit, 1 = slow, 255 = fast 62 | fadeToBlackBy(leds, 1, 32); 63 | } 64 | 65 | getSample(); // Sample the microphone. 66 | agcPI(); // Calculated the PI adjusted value as samplePI. 67 | ledShow(); 68 | FastLED.show(); 69 | 70 | } // loop() 71 | 72 | 73 | 74 | void ledShow() { 75 | 76 | leds[(millis() % (NUM_LEDS-1)) +1 ] = CHSV(samplePI, 255, samplePI); 77 | if (samplePeak) {leds[0] = CHSV(0,0,128); samplePeak = 0;} // Add a peak twinkle to the first LED. 78 | 79 | } // ledShow() 80 | 81 | 82 | 83 | void getSample() { 84 | 85 | int16_t micIn; // Current sample starts with negative values and large values, which is why it's 16 bit signed. 86 | static long peakTime; 87 | 88 | micIn = analogRead(MIC_PIN); // Poor man's analog Read. 89 | micLev = ((micLev * 31) + micIn) / 32; // Smooth it out over the last 32 samples for automatic centering. 90 | micIn -= micLev; // Let's center it to 0 now. 91 | micIn = abs(micIn); // And get the absolute value of each sample. 92 | sample = (micIn <= squelch) ? 0 : (sample + micIn)/2; // Using a ternary operator, the resultant sample is either 0 or it's a bit smoothed out with the last sample. 93 | sampleAvg = ((sampleAvg * 31) + sample) / 32; // Smooth it out over the last 32 samples. 94 | 95 | if (sample > (sampleAvg+maxVol) && millis() > (peakTime + 50)) { // Poor man's beat detection by seeing if sample > Average + some value. 96 | samplePeak = 1; 97 | peakTime=millis(); 98 | } // Then we got a peak, else we don't. Display routines need to reset the samplepeak value in case they miss the trigger. 99 | 100 | } // getSample() 101 | 102 | 103 | 104 | void agcPI() { // A PI Control loop to automatically adjust sound sensitivity. 105 | 106 | float sensitivity; // Sensitivity is calculated by the PI routine. 107 | static float startt = 0; // Accumulated (or integral) value for Ki. 108 | 109 | err = targetAgc - samplePIAvg; // Calculate the average error from the target. Is continuously going up. This should be closed loop. 110 | startt = constrain(startt + err, minn, maxx); // Calculate summation (Integral) error, but constrain it. 111 | 112 | sensitivity = kp * err + ki * startt; // Sensitivity is the direct (Proportional) error plus the above Integral error. 113 | if (sensitivity <= 3000) sensitivity = 3000; // Minimum sensitity multiplier should be 1. Andrew Tuline. I don't want divide by 0. 114 | samplePI = abs(sample * sensitivity / 3000); 115 | if(samplePI > 255) samplePI = 255; 116 | 117 | samplePIAvg = ((samplePIAvg * 15) + samplePI) / 16; // Smooth it out over the last 16 samples and use as feedback for the (now closed) PI loop. 118 | 119 | //------------ Oscilloscope output --------------------------- 120 | Serial.print(sample); Serial.print(" "); 121 | // Serial.print(sampleAvg); Serial.print(" "); 122 | // Serial.print(micLev); Serial.print(" "); 123 | // Serial.print(err); Serial.print(" "); 124 | // Serial.print(startt); Serial.print(" "); 125 | Serial.print(samplePI); Serial.print(" "); 126 | // Serial.print(samplePIAvg); Serial.print(" "); 127 | // Serial.print(sensitivity/3000); Serial.print(" "); 128 | // Serial.print(targetAgc); Serial.print(" "); 129 | Serial.print(0); Serial.print(" "); 130 | Serial.println(" "); 131 | 132 | } // agcPI() 133 | -------------------------------------------------------------------------------- /Tutorial/centering_1/centering_1.ino: -------------------------------------------------------------------------------- 1 | /* Sound sampling - Pre-defined centering. 2 | * 3 | * By: Andrew Tuline 4 | * 5 | * Date: Jan 2020 6 | * 7 | * Basic code to read from the Sparkfun INMP401 microphone at 5V on Arduino Nano and UNO and center it. 8 | * 9 | */ 10 | 11 | #define MIC_PIN 5 // Microphone, or A0 on a WeMOS D1 Mini. 12 | #define DC_OFFSET 510 // DC offset in mic signal. I subtract this value from the raw sample. 13 | 14 | 15 | void setup() { 16 | Serial.begin(115200); 17 | analogReference(EXTERNAL); // Comment out this line for 3.3V Arduino's, or 5V microphones. 18 | delay(1000); 19 | } // setup() 20 | 21 | 22 | 23 | void loop() { 24 | getSample(); // Sample the sounds. 25 | } // loop() 26 | 27 | 28 | 29 | void getSample() { 30 | 31 | uint16_t micIn; // Current sample was 0-1023. 32 | int16_t micLev; // Here, we subtract the offset, so this should be 16 bit signed. 33 | 34 | micIn = analogRead(MIC_PIN); // Sample the microphone. 35 | micLev = micIn - DC_OFFSET; // Signed value centering around 0. 36 | 37 | Serial.print(micLev); Serial.print(" "); 38 | Serial.print(20); Serial.print(" "); // Fake out the 'auto' re-sizing for the serial plotter in the Arduino IDE. 39 | Serial.print(-20); Serial.println(" "); 40 | 41 | } // getSample() 42 | -------------------------------------------------------------------------------- /Tutorial/centering_2/centering_2.ino: -------------------------------------------------------------------------------- 1 | /* centering_2 with for loop based averaging. 2 | * 3 | * By: Andrew Tuline 4 | * 5 | * Date: January 2020 6 | * 7 | * Centering sound samples using a for loop and integer averaging. Average is about 510. 8 | * 9 | * This is slow. 10 | * 11 | */ 12 | 13 | 14 | #define MIC_PIN 5 // Microphone 15 | #define NSAMPLES 32 // Number of samples. 16 | 17 | void setup() { 18 | Serial.begin(115200); 19 | analogReference(EXTERNAL); // Comment out this line for 3.3V Arduino's. 20 | delay(1000); 21 | } // setup() 22 | 23 | 24 | 25 | void loop() { 26 | getSample(); // Sample the sounds. 27 | } // loop() 28 | 29 | 30 | 31 | void getSample() { 32 | 33 | uint16_t micIn; 34 | long sampleTotal = 0; // Could easily use a uint16_t (0 to 65535). 35 | uint16_t micLev = 0; // Not using signed numbers for this. 36 | 37 | for (int i = 0; i (sampleAvg+maxVol) && millis() > (peakTime + 50)) { // Poor man's beat detection by seeing if sample > Average + some value. 50 | samplePeak = 1; // Then we got a peak, else we don't. Display routines need to reset the samplepeak value in case they miss the trigger. 51 | peakTime=millis(); 52 | } 53 | 54 | Serial.print(sample); Serial.print(" "); 55 | Serial.print(sampleAvg); Serial.print(" "); 56 | Serial.print(samplePeak*60); Serial.print(" "); 57 | Serial.print(0); Serial.print(" "); 58 | Serial.print(60); Serial.print(" "); 59 | Serial.println(" "); 60 | 61 | 62 | samplePeak = 0; 63 | 64 | } // getSample() 65 | -------------------------------------------------------------------------------- /Tutorial/squelch/squelch.ino: -------------------------------------------------------------------------------- 1 | /* squelch of background noise in sampled sounds. 2 | * 3 | * By: Andrew Tuline 4 | * 5 | * Date: January 2020 6 | * 7 | * 8 | */ 9 | 10 | 11 | #define MIC_PIN 5 // Microphone 12 | 13 | float micLev; 14 | 15 | 16 | void setup() { 17 | Serial.begin(115200); 18 | analogReference(EXTERNAL); // Comment out this line for 3.3V Arduino's. 19 | delay(1000); 20 | } // setup() 21 | 22 | 23 | 24 | void loop() { 25 | getSample(); // Sample the sounds. 26 | } // loop() 27 | 28 | 29 | 30 | void getSample() { 31 | 32 | uint8_t squelch = 7; // Let's try a squelch value of 7. 33 | int16_t micIn; 34 | static uint16_t sample; 35 | 36 | micIn = analogRead(MIC_PIN); // Sample the microphone. Range will result in 0 to 1023. 37 | micLev = ((micLev * 31) + micIn) / 32; // Smooth it out over the last 32 samples. 38 | 39 | micIn = micIn - micLev; 40 | micIn = abs(micIn); 41 | 42 | sample = (micIn <= squelch) ? 0 : (sample + micIn) / 2; // Using a ternary operator to smooth out the last 2 (or 4 if you want) samples. Less glitchy this way. 43 | 44 | Serial.print(micIn); Serial.print(" "); 45 | Serial.print(sample); Serial.print(" "); 46 | Serial.println(" "); 47 | 48 | } // getSample() 49 | -------------------------------------------------------------------------------- /agcAvg/agcAvg.ino: -------------------------------------------------------------------------------- 1 | /* agcAvg 2 | * 3 | * By: Andrew Tuline 4 | * 5 | * Date: Jan, 2020 6 | * 7 | * An Automatic Gain Control for a microphone on an Arduino. 8 | * 9 | * This version uses simple averaging of 32 samples against a setpoint. Simple, but at least it works. 10 | * 11 | * It also includes a ghetto peak detection capability, which is displayed on led[0]. 12 | * 13 | */ 14 | 15 | 16 | //#define FASTLED_ALLOW_INTERRUPTS 0 // Used for ESP8266. 17 | #include // FastLED library. 18 | 19 | #define MIC_PIN 5 // Analog port for microphone 20 | uint8_t squelch = 7; // Anything below this is background noise, so we'll make it '0'. 21 | int sample; // Current sample. 22 | float sampleAvg; // Smoothed Average. 23 | uint8_t maxVol = 11; // Reasonable value for constant volume for 'peak detector', as it won't always trigger. 24 | bool samplePeak = 0; // Boolean flag for peak. Responding routine must reset this flag. 25 | 26 | int sampleAgc, multAgc; 27 | uint8_t targetAgc = 60; // This is our setPoint at 20% of max for the adjusted output. 28 | 29 | 30 | // Fixed definitions cannot change on the fly. 31 | #define LED_DT 12 // Data pin to connect to the strip. 32 | #define LED_CK 11 // Clock pin for WS2801 or APA102. 33 | #define COLOR_ORDER GRB // It's GRB for WS2812 and BGR for APA102. 34 | #define LED_TYPE WS2812 // Using APA102, WS2812, WS2801. Don't forget to modify LEDS.addLeds to suit. 35 | #define NUM_LEDS 30 // Number of LED's. 36 | 37 | uint8_t max_bright = 255; // Overall brightness. 38 | struct CRGB leds[NUM_LEDS]; // Initialize our LED array. 39 | 40 | 41 | 42 | void setup() { 43 | Serial.begin(115200); // Initialize serial port for debugging. 44 | delay(1000); 45 | analogReference(EXTERNAL); // Nano or other 5V AVR8 when using a 3.3V microphone. 46 | LEDS.addLeds(leds, NUM_LEDS); // Use this for WS2812 47 | FastLED.setBrightness(max_bright); 48 | FastLED.setMaxPowerInVoltsAndMilliamps(5, 500); // FastLED Power management set at 5V, 500mA 49 | } // setup() 50 | 51 | 52 | 53 | void loop() { 54 | 55 | EVERY_N_MILLIS(10) { 56 | fadeToBlackBy(leds, NUM_LEDS, 4); // 8 bit, 1 = slow, 255 = fast 57 | fadeToBlackBy(leds, 1, 32); 58 | } 59 | 60 | getSample(); // Sample the microphone. 61 | agcAvg(); // Calculate the adjusted value as sampleAvg. 62 | ledShow(); 63 | FastLED.show(); 64 | 65 | } // loop() 66 | 67 | 68 | 69 | void ledShow() { 70 | 71 | if (samplePeak == 1) { leds[0] = CRGB::Gray; samplePeak = 0;} 72 | leds[(millis() % (NUM_LEDS-1)) +1] = CHSV(sampleAgc, 255, sampleAgc); 73 | 74 | } // ledShow() 75 | 76 | 77 | 78 | void getSample() { 79 | 80 | static float micLev; // Used to convert returned value to have '0' as minimum. 81 | int16_t micIn; // Current sample starts with negative values and large values, which is why it's 16 bit signed. 82 | static long peakTime; 83 | 84 | micIn = analogRead(MIC_PIN); // Poor man's analog Read. 85 | micLev = ((micLev * 31) + micIn) / 32; // Smooth it out over the last 32 samples for automatic centering. 86 | micIn -= micLev; // Let's center it to 0 now. 87 | micIn = abs(micIn); // And get the absolute value of each sample. 88 | sample = (micIn <= squelch) ? 0 : (sample + micIn) / 2; // Using a ternary operator, the resultant sample is either 0 or it's a bit smoothed out with the last sample. 89 | sampleAvg = ((sampleAvg * 31) + sample) / 32; // Smooth it out over the last 32 samples. 90 | 91 | if (sample > (sampleAvg+maxVol) && millis() > (peakTime + 50)) { // Poor man's beat detection by seeing if sample > Average + some value. 92 | samplePeak = 1; // Then we got a peak, else we don't. Display routines need to reset the samplepeak value in case they miss the trigger. 93 | peakTime=millis(); 94 | } 95 | 96 | } // getSample() 97 | 98 | 99 | 100 | void agcAvg() { // A simple averaging multiplier to automatically adjust sound sensitivity. 101 | 102 | multAgc = (sampleAvg < 1) ? targetAgc : targetAgc / sampleAvg; // Make the multiplier so that sampleAvg * multiplier = setpoint 103 | sampleAgc = sample * multAgc; 104 | if (sampleAgc > 255) sampleAgc = 255; 105 | 106 | //------------ Oscilloscope output --------------------------- 107 | // Serial.print(targetAgc); Serial.print(" "); 108 | // Serial.print(multAgc); Serial.print(" "); 109 | // Serial.print(sampleAgc); Serial.print(" "); 110 | 111 | // Serial.print(micLev); Serial.print(" "); 112 | // Serial.print(sample); Serial.println(" "); 113 | // Serial.print(sampleAvg); Serial.println(" "); 114 | // Serial.print(samplePeak); Serial.print(" "); samplePeak = 0; 115 | // Serial.print(100); Serial.print(" "); 116 | // Serial.print(0); Serial.print(" "); 117 | // Serial.println(" "); 118 | 119 | } // agcAvg() 120 | -------------------------------------------------------------------------------- /agcAvg_Pal/agcAvg_Pal.ino: -------------------------------------------------------------------------------- 1 | /* agcAvg_Pal 2 | * 3 | * By: Andrew Tuline 4 | * 5 | * Date: Jan, 2020 6 | * 7 | * A palette enabled Automatic Gain Control for a microphone on an Arduino. 8 | * 9 | * This version uses simple averaging of 32 samples against a setpoint. Simple, but at least it works. 10 | * 11 | * It also includes a ghetto peak detection capability, which is displayed on led[0]. 12 | * 13 | */ 14 | 15 | 16 | //#define FASTLED_ALLOW_INTERRUPTS 0 // Used for ESP8266. 17 | #include // FastLED library. 18 | 19 | #define MIC_PIN 5 // Analog port for microphone 20 | uint8_t squelch = 7; // Anything below this is background noise, so we'll make it '0'. 21 | int sample; // Current sample. 22 | float sampleAvg = 0; // Smoothed Average. 23 | float micLev = 0; // Used to convert returned value to have '0' as minimum. 24 | uint8_t maxVol = 11; // Reasonable value for constant volume for 'peak detector', as it won't always trigger. 25 | bool samplePeak = 0; // Boolean flag for peak. Responding routine must reset this flag. 26 | 27 | 28 | int sampleAgc, multAgc; 29 | uint8_t targetAgc = 60; // This is our setPoint at 20% of max for the adjusted output. 30 | 31 | 32 | 33 | // Fixed definitions cannot change on the fly. 34 | #define LED_DT 12 // Data pin to connect to the strip. 35 | #define LED_CK 11 // Clock pin for WS2801 or APA102. 36 | #define COLOR_ORDER GRB // It's GRB for WS2812 and BGR for APA102. 37 | #define LED_TYPE WS2812 // Using APA102, WS2812, WS2801. Don't forget to modify LEDS.addLeds to suit. 38 | #define NUM_LEDS 30 // Number of LED's. 39 | 40 | uint8_t max_bright = 255; // Overall brightness. 41 | struct CRGB leds[NUM_LEDS]; // Initialize our LED array. 42 | 43 | // Palette definitions 44 | CRGBPalette16 currentPalette = PartyColors_p; 45 | CRGBPalette16 targetPalette = PartyColors_p; 46 | TBlendType currentBlending = LINEARBLEND; // NOBLEND or LINEARBLEND 47 | 48 | 49 | 50 | void setup() { 51 | Serial.begin(115200); // Initialize serial port for debugging. 52 | delay(1000); 53 | analogReference(EXTERNAL); // Nano or other 5V AVR8 when using a 3.3V microphone. 54 | LEDS.addLeds(leds, NUM_LEDS); // Use this for WS2812 55 | FastLED.setBrightness(max_bright); 56 | FastLED.setMaxPowerInVoltsAndMilliamps(5, 500); // FastLED Power management set at 5V, 500mA 57 | } // setup() 58 | 59 | 60 | 61 | void loop() { 62 | 63 | EVERY_N_MILLISECONDS(100) { 64 | uint8_t maxChanges = 24; 65 | nblendPaletteTowardPalette(currentPalette, targetPalette, maxChanges); // AWESOME palette blending capability. 66 | } 67 | 68 | EVERY_N_MILLIS(10) { 69 | fadeToBlackBy(leds, NUM_LEDS, 4); // 8 bit, 1 = slow, 255 = fast 70 | fadeToBlackBy(leds, 1, 32); 71 | } 72 | 73 | EVERY_N_SECONDS(5) { // Change the target palette to a random one every 5 seconds. 74 | static uint8_t baseC = random8(); // You can use this as a baseline colour if you want similar hues in the next line. 75 | targetPalette = CRGBPalette16(CHSV(random8(), 255, random8(128, 255)), CHSV(random8(), 255, random8(128, 255)), CHSV(random8(), 192, random8(128, 255)), CHSV(random8(), 255, random8(128, 255))); 76 | } 77 | 78 | getSample(); // Sample the microphone. 79 | agcAvg(); // Calculate the adjusted value as sampleAvg. 80 | ledShow(); 81 | FastLED.show(); 82 | 83 | } // loop() 84 | 85 | 86 | 87 | void ledShow() { 88 | 89 | if (samplePeak == 1) { leds[0] = CRGB::Gray; samplePeak = 0;} 90 | leds[(millis() % (NUM_LEDS-1)) +1] = ColorFromPalette(currentPalette, sampleAgc, sampleAgc, currentBlending); 91 | 92 | } // ledShow() 93 | 94 | 95 | 96 | void getSample() { 97 | 98 | int16_t micIn; // Current sample starts with negative values and large values, which is why it's 16 bit signed. 99 | static long peakTime; 100 | 101 | micIn = analogRead(MIC_PIN); // Poor man's analog Read. 102 | micLev = ((micLev * 31) + micIn) / 32; // Smooth it out over the last 32 samples for automatic centering. 103 | micIn -= micLev; // Let's center it to 0 now. 104 | micIn = abs(micIn); // And get the absolute value of each sample. 105 | sample = (micIn <= squelch) ? 0 : (sample + micIn)/2; // Using a ternary operator, the resultant sample is either 0 or it's a bit smoothed out with the last sample. 106 | sampleAvg = ((sampleAvg * 31) + sample) / 32; // Smooth it out over the last 32 samples. 107 | 108 | if (sample > (sampleAvg+maxVol) && millis() > (peakTime + 50)) { // Poor man's beat detection by seeing if sample > Average + some value. 109 | samplePeak = 1; 110 | peakTime=millis(); 111 | } // Then we got a peak, else we don't. Display routines need to reset the samplepeak value in case they miss the trigger. 112 | 113 | } // getSample() 114 | 115 | 116 | 117 | void agcAvg() { // A simple averaging multiplier to automatically adjust sound sensitivity. 118 | 119 | multAgc = (sampleAvg < 1) ? targetAgc : targetAgc / sampleAvg; // Make the multiplier so that sampleAvg * multiplier = setpoint 120 | sampleAgc = sample * multAgc; 121 | if (sampleAgc > 255) sampleAgc = 255; 122 | 123 | //------------ Oscilloscope output --------------------------- 124 | // Serial.print(targetAgc); Serial.print(" "); 125 | // Serial.print(multAgc); Serial.print(" "); 126 | // Serial.print(sampleAgc); Serial.print(" "); 127 | 128 | // Serial.print(sample); Serial.print(" "); 129 | // Serial.print(sampleAvg); Serial.print(" "); 130 | // Serial.print(micLev); Serial.print(" "); 131 | // Serial.print(samplePeak); Serial.print(" "); samplePeak = 0; 132 | // Serial.print(100); Serial.print(" "); 133 | // Serial.print(0); Serial.print(" "); 134 | Serial.println(" "); 135 | 136 | } // agcAvg() 137 | -------------------------------------------------------------------------------- /agcPI/agcPI.ino: -------------------------------------------------------------------------------- 1 | /* agcPI 2 | * 3 | * By: Andrew Tuline 4 | * 5 | * Date: Jan, 2020 6 | * 7 | * An Automatic Gain Control for a microphone on an Arduino. 8 | * 9 | * This version uses a PI (proportional integral) control loop. 10 | * 11 | * See: https://en.wikipedia.org/wiki/PID_controller 12 | * 13 | * It also includes a ghetto peak detection capability, which is displayed on led[0]. 14 | * 15 | */ 16 | 17 | //#define FASTLED_ALLOW_INTERRUPTS 0 // Used for ESP8266. 18 | #include // FastLED library. 19 | 20 | #define MIC_PIN A5 // Nano or A0 on ESP8266 21 | uint8_t squelch = 7; // Anything below this is background noise, so we'll make it '0'. 22 | int sample; // Current sample. 23 | float sampleAvg = 0; // Can be used for smoothing signals. 24 | float micLev = 0; // Used to convert returned value to have '0' as minimum. 25 | uint8_t maxVol = 11; // Reasonable value for constant volume (above average) for 'peak detector'. 26 | bool samplePeak = 0; // Boolean flag for peak detected. Responding routine must reset this flag. 27 | 28 | uint8_t targetAgc = 60; // This is our setPoint at ~20% of max for the adjusted output. 29 | float kp = 2, ki = 4; // Proportional and Integral tuning constants. Kept as floating point in case we find better tuning. 30 | int err; // Current offset from our target. 31 | int minn = -20000, maxx = 20000; // Keep everything in check with these values. 32 | int samplePI; // Sensitivity is calculated by the PI routine. 33 | float samplePIAvg; // Calculated and stored average calculated sample is used for closed loop feedback. 34 | 35 | // Fixed definitions cannot change on the fly. 36 | #define LED_DT 12 // Data pin to connect to the strip. 37 | #define LED_CK 11 // Clock pin for WS2801 or APA102. 38 | #define COLOR_ORDER GRB // It's GRB for WS2812 and BGR for APA102. 39 | #define LED_TYPE WS2812 // Using APA102, WS2812, WS2801. Don't forget to modify LEDS.addLeds to suit. 40 | #define NUM_LEDS 30 // Number of LED's. 41 | 42 | uint8_t max_bright = 255; // Overall brightness. 43 | struct CRGB leds[NUM_LEDS]; // Initialize our LED array. 44 | 45 | 46 | 47 | void setup() { 48 | Serial.begin(115200); // Initialize serial port for debugging. 49 | delay(1000); 50 | analogReference(EXTERNAL); // Nano or other 5V AVR8 when using a 3.3V microphone. 51 | LEDS.addLeds(leds, NUM_LEDS); // Use this for WS2812 52 | FastLED.setBrightness(max_bright); 53 | FastLED.setMaxPowerInVoltsAndMilliamps(5, 500); // FastLED Power management set at 5V, 500mA 54 | } // setup() 55 | 56 | 57 | 58 | void loop() { 59 | 60 | EVERY_N_MILLIS(10) { 61 | fadeToBlackBy(leds, NUM_LEDS, 4); // 8 bit, 1 = slow, 255 = fast 62 | fadeToBlackBy(leds, 1, 32); 63 | } 64 | 65 | getSample(); // Sample the microphone. 66 | agcPI(); // Calculated the PI adjusted value as samplePI. 67 | ledShow(); 68 | FastLED.show(); 69 | 70 | } // loop() 71 | 72 | 73 | 74 | void ledShow() { 75 | 76 | leds[(millis() % (NUM_LEDS-1)) +1 ] = CHSV(samplePI, 255, samplePI); 77 | if (samplePeak) {leds[0] = CHSV(0,0,128);} // Add a peak twinkle to the first LED. 78 | 79 | } // ledShow() 80 | 81 | 82 | 83 | void getSample() { 84 | 85 | int16_t micIn; // Current sample starts with negative values and large values, which is why it's 16 bit signed. 86 | static long peakTime; 87 | 88 | micIn = analogRead(MIC_PIN); // Poor man's analog Read. 89 | micLev = ((micLev * 31) + micIn) / 32; // Smooth it out over the last 32 samples for automatic centering. 90 | micIn -= micLev; // Let's center it to 0 now. 91 | micIn = abs(micIn); // And get the absolute value of each sample. 92 | sample = (micIn <= squelch) ? 0 : (sample + micIn)/2; // Using a ternary operator, the resultant sample is either 0 or it's a bit smoothed out with the last sample. 93 | sampleAvg = ((sampleAvg * 31) + sample) / 32; // Smooth it out over the last 32 samples. 94 | 95 | if (millis() > (peakTime+50)) samplePeak = 0; // Reset peak if it's been > 50ms. 96 | 97 | if (sample > (sampleAvg+maxVol) && millis() > (peakTime + 100)) { // Poor man's beat detection by seeing if sample > Average + some value. 98 | samplePeak = 1; 99 | peakTime=millis(); 100 | } // Then we got a peak, else we don't. Display routines need to reset the samplepeak value in case they miss the trigger. 101 | 102 | } // getSample() 103 | 104 | 105 | 106 | void agcPI() { // A PI Control loop to automatically adjust sound sensitivity. 107 | 108 | float sensitivity; // Sensitivity is calculated by the PI routine. 109 | static float startt = 0; // Accumulated (or integral) value for Ki. 110 | 111 | err = targetAgc - samplePIAvg; // Calculate the average error from the target. Is continuously going up. This should be closed loop. 112 | startt = constrain(startt + err, minn, maxx); // Calculate summation (Integral) error, but constrain it. 113 | 114 | sensitivity = kp * err + ki * startt; // Sensitivity is the direct (Proportional) error plus the above Integral error. 115 | if (sensitivity <= 3000) sensitivity = 3000; // Minimum sensitity multiplier should be 1. Andrew Tuline. I don't want divide by 0. 116 | samplePI = abs(sample * sensitivity / 3000); 117 | if(samplePI > 255) samplePI = 255; 118 | 119 | samplePIAvg = ((samplePIAvg * 15) + samplePI) / 16; // Smooth it out over the last 16 samples and use as feedback for the (now closed) PI loop. 120 | 121 | //------------ Oscilloscope output --------------------------- 122 | // Serial.print(sample); Serial.print(" "); 123 | // Serial.print(sampleAvg); Serial.print(" "); 124 | // Serial.print(micLev); Serial.print(" "); 125 | // Serial.print(err); Serial.print(" "); 126 | // Serial.print(startt); Serial.print(" "); 127 | // Serial.print(samplePI); Serial.print(" "); 128 | // Serial.print(samplePIAvg); Serial.print(" "); 129 | // Serial.print(sensitivity/3000); Serial.print(" "); 130 | // Serial.print(targetAgc); Serial.print(" "); 131 | Serial.print(0); Serial.print(" "); 132 | Serial.println(" "); 133 | 134 | } // agcPI() 135 | -------------------------------------------------------------------------------- /agcPI_Pal/agcPI_Pal.ino: -------------------------------------------------------------------------------- 1 | /* agcPI_Pal 2 | * 3 | * By: Andrew Tuline 4 | * 5 | * Date: Jan, 2020 6 | * 7 | * A palette enabled Automatic Gain Control for a microphone on an Arduino. 8 | * 9 | * This palette enabled version uses a PI (proportional integral) control loop. 10 | * 11 | * See: https://en.wikipedia.org/wiki/PID_controller 12 | * 13 | * It also includes a ghetto peak detection capability, which is displayed on led[0]. 14 | * 15 | */ 16 | 17 | 18 | //#define FASTLED_ALLOW_INTERRUPTS 0 // Used for ESP8266. 19 | #include // FastLED library. 20 | 21 | #define MIC_PIN A5 // Nano or A0 on ESP8266 22 | uint8_t squelch = 7; // Anything below this is background noise, so we'll make it '0'. 23 | int sample; // Current sample. 24 | float sampleAvg = 0; // Can be used for smoothing signals. 25 | float micLev = 0; // Used to convert returned value to have '0' as minimum. 26 | uint8_t maxVol = 11; // Reasonable value for constant volume (above average) for 'peak detector'. 27 | bool samplePeak = 0; // Boolean flag for peak detected. Responding routine must reset this flag. 28 | 29 | uint8_t targetAgc = 60; // This is our setPoint at ~20% of max for the adjusted output. 30 | float kp = 2, ki = 4; // Proportional and Integral tuning constants. Kept as floating point in case we find better tuning. 31 | int err; // Current offset from our target. 32 | int minn = -20000, maxx = 20000; // Keep everything in check with these values. 33 | int samplePI; // Sensitivity is calculated by the PI routine. 34 | float samplePIAvg; // Calculated and stored average calculated sample is used for closed loop feedback. 35 | 36 | // Fixed definitions cannot change on the fly. 37 | #define LED_DT 12 // Data pin to connect to the strip. 38 | #define LED_CK 11 // Clock pin for WS2801 or APA102. 39 | #define COLOR_ORDER GRB // It's GRB for WS2812 and BGR for APA102. 40 | #define LED_TYPE WS2812 // Using APA102, WS2812, WS2801. Don't forget to modify LEDS.addLeds to suit. 41 | #define NUM_LEDS 30 // Number of LED's. 42 | 43 | uint8_t max_bright = 255; // Overall brightness. 44 | struct CRGB leds[NUM_LEDS]; // Initialize our LED array. 45 | 46 | CRGBPalette16 currentPalette = PartyColors_p; 47 | CRGBPalette16 targetPalette = PartyColors_p; 48 | TBlendType currentBlending = LINEARBLEND; // NOBLEND or LINEARBLEND 49 | 50 | 51 | 52 | void setup() { 53 | Serial.begin(115200); // Initialize serial port for debugging. 54 | delay(1000); 55 | analogReference(EXTERNAL); // Nano or other 5V AVR8 when using a 3.3V microphone. 56 | LEDS.addLeds(leds, NUM_LEDS); // Use this for WS2812 57 | FastLED.setBrightness(max_bright); 58 | FastLED.setMaxPowerInVoltsAndMilliamps(5, 500); // FastLED Power management set at 5V, 500mA 59 | } // setup() 60 | 61 | 62 | 63 | void loop() { 64 | 65 | EVERY_N_MILLISECONDS(100) { 66 | uint8_t maxChanges = 24; 67 | nblendPaletteTowardPalette(currentPalette, targetPalette, maxChanges); // AWESOME palette blending capability. 68 | } 69 | 70 | EVERY_N_SECONDS(5) { // Change the target palette to a random one every 5 seconds. 71 | static uint8_t baseC = random8(); // You can use this as a baseline colour if you want similar hues in the next line. 72 | targetPalette = CRGBPalette16(CHSV(random8(), 255, random8(128, 255)), CHSV(random8(), 255, random8(128, 255)), CHSV(random8(), 192, random8(128, 255)), CHSV(random8(), 255, random8(128, 255))); 73 | } 74 | 75 | EVERY_N_MILLIS(10) { 76 | fadeToBlackBy(leds, NUM_LEDS, 4); // 8 bit, 1 = slow, 255 = fast 77 | fadeToBlackBy(leds, 1, 32); 78 | } 79 | 80 | getSample(); // Sample the microphone. 81 | agcPI(); // Calculated the PI adjusted value as samplePI. 82 | ledShow(); 83 | 84 | FastLED.show(); 85 | 86 | } // loop() 87 | 88 | 89 | 90 | void ledShow() { 91 | 92 | if (samplePeak == 1) { leds[0] = CRGB::Gray; samplePeak = 0;} 93 | leds[(millis() % (NUM_LEDS-1)) +1] = ColorFromPalette(currentPalette, samplePI, samplePI, currentBlending); 94 | 95 | } // ledShow() 96 | 97 | 98 | 99 | void getSample() { 100 | 101 | int16_t micIn; // Current sample starts with negative values and large values, which is why it's 16 bit signed. 102 | static long peakTime; 103 | 104 | micIn = analogRead(MIC_PIN); // Poor man's analog Read. 105 | micLev = ((micLev * 31) + micIn) / 32; // Smooth it out over the last 32 samples for automatic centering. 106 | micIn -= micLev; // Let's center it to 0 now. 107 | micIn = abs(micIn); // And get the absolute value of each sample. 108 | sample = (micIn <= squelch) ? 0 : (sample + micIn)/2; // Using a ternary operator, the resultant sample is either 0 or it's a bit smoothed out with the last sample. 109 | sampleAvg = ((sampleAvg * 31) + sample) / 32; // Smooth it out over the last 32 samples. 110 | 111 | if (sample > (sampleAvg+maxVol) && millis() > (peakTime + 50)) { // Poor man's beat detection by seeing if sample > Average + some value. 112 | samplePeak = 1; 113 | peakTime=millis(); 114 | } // Then we got a peak, else we don't. Display routines need to reset the samplepeak value in case they miss the trigger. 115 | 116 | } // getSample() 117 | 118 | 119 | 120 | void agcPI() { // A PI Control loop to automatically adjust sound sensitivity. 121 | 122 | float sensitivity; // Sensitivity is calculated by the PI routine. 123 | static float startt = 0; // Accumulated (or integral) value for Ki. 124 | 125 | err = targetAgc - samplePIAvg; // Calculate the average error from the target. Is continuously going up. 126 | startt = constrain(startt + err, minn, maxx); // Calculate summation (Integral) error, but constrain it. 127 | 128 | sensitivity = kp * err + ki * startt; // Sensitivity is the direct (Proportional) error plus the above Integral error. 129 | if (sensitivity <= 3000) sensitivity = 3000; // Minimum sensitity multiplier should be 1. Andrew Tuline. 130 | samplePI = abs(sample * sensitivity / 3000); 131 | if(samplePI > 255) samplePI = 255; 132 | 133 | samplePIAvg = ((samplePIAvg * 15) + samplePI) / 16; // Smooth it out over the last 16 samples and use as feedback for the PI loop. 134 | 135 | //------------ Oscilloscope output --------------------------- 136 | // Serial.print(sample); Serial.print(" "); 137 | // Serial.print(sampleAvg); Serial.print(" "); 138 | // Serial.proint(micLev); Serial.print(" "); 139 | // Serial.print(err); Serial.print(" "); 140 | // Serial.print(startt); Serial.print(" "); 141 | // Serial.print(samplePI); Serial.print(" "); 142 | // Serial.print(samplePIAvg); Serial.print(" "); 143 | // Serial.print(sensitivity/3000); Serial.print(" "); 144 | // Serial.print(targetAgc); Serial.print(" "); 145 | Serial.print(100); Serial.print(" "); 146 | Serial.print(0); Serial.print(" "); 147 | Serial.println(" "); 148 | 149 | } // agcPI() 150 | -------------------------------------------------------------------------------- /fht_log_fast/fht_log_fast.ino: -------------------------------------------------------------------------------- 1 | /* fht_log_fast 2 | * 3 | * By: Andrew Tuline 4 | * 5 | * Date: Mar, 2019 6 | * 7 | * 8 | * Why use a 7 band MSGEQ7 graphic equalizer chip when you can get many times more frequency bins with software alone and on an Arduino UNO to boot? 9 | * 10 | * This example combines high speed A/D conversion, FHT (Fast Hartley Transform) pitch detection combined with simple FastLED library display using 11 | * an Arduino Nano, an ADMP401 MEMS microphone and a strip of APA102 led's. 12 | * 13 | * 14 | * The advantage of using MSGEQ7 chips is that the coding is relatively simple. The disadvantage is that: 15 | * 16 | * - you need extra hardware. 17 | * - you get a measly 7 frequency bins. 18 | * - the results can often be jittery. 19 | * 20 | * By using the Open Music Labs FHT (Fast Hartley Transform) library in conjunction with high speed A/D conversion, you can perform pitch detection on an 21 | * Arduino UNO with much more capability than an MSGEQ7 chip. Oh, and that library gives you about a 5 millisecond conversion, and combined with FastLED 22 | * you can get on the order of 125 frames per second. That's no slouch for an 8 bit 16MHz microcontroller. 23 | * 24 | * The FHT library is available at http://wiki.openmusiclabs.com/wiki/ArduinoFHT 25 | * 26 | * The A/D conversion uses direct port manipulation and can run at 19KHz, 38KHz or even higher as opposed to 8KHz for a standard analogRead() conversion. 27 | * Furthermore, by disabling interrupts for a short period of time, you can reduce jitter during the sampling. This has a side effect of making 3 pin WS2812 28 | * displays less reliable and, as a result, we'll use 4 pin APA102 LED's instead. Reference: 29 | * 30 | * https://github.com/FastLED/FastLED/wiki/Interrupt-problems 31 | * 32 | * 33 | * The microphone used for this routine is a Sparkfun ADMP401 MEMS microphone, which runs at 3.3V. With this microphone, we need to tie the AREF pin to 3.3V, 34 | * and in setup(), perform: 35 | * 36 | * analogReference(EXTERNAL); 37 | * 38 | * or use the direct port equivalent, which is: 39 | * 40 | * ADMUX |= (0 << REFS0); 41 | * 42 | * 43 | * Testing has been performed with a an Android based Function Generator by Keuwlsoft. With so many frequency bins to choose from, you can select the ranges you 44 | * want to work with and discard the rest. 45 | * 46 | */ 47 | 48 | 49 | #define qsubd(x, b) ((x>b)?b:0) // A digital unsigned subtraction macro. if result <0, then => 0. Otherwise, take on fixed value. 50 | #define qsuba(x, b) ((x>b)?x-b:0) // Unsigned subtraction macro. if result <0, then => 0. 51 | 52 | // FHT Definitions 53 | #define LOG_OUT 1 // Use logarithmic based bins (is required for the library to run). 54 | #define FHT_N 256 // Set to 256 point fht. Any less, and the upper ranges won't work well. 55 | #define DC_OFFSET 509 // DC offset in mic signal. Should probably be about 512. 56 | #define MIC_PIN 5 // We're using A5. 57 | 58 | #include // FHT library at http://wiki.openmusiclabs.com/wiki/ArduinoFHT 59 | 60 | #include "FastLED.h" // FastLED library at https://github.com/FastLED/FastLED 61 | 62 | #if FASTLED_VERSION < 3001000 63 | #error "Requires FastLED 3.1 or later; check github for latest code." 64 | #endif 65 | 66 | // Fixed definitions cannot change on the fly. 67 | #define LED_DT 12 // Data pin to connect to the strip. 68 | #define LED_CK 11 // Clock pin for APA102 or WS2801 69 | #define COLOR_ORDER BGR // It's GRB for WS2812B 70 | #define LED_TYPE APA102 // What kind of strip are you using (APA102, WS2801 or WS2812B) 71 | #define NUM_LEDS 40 // Number of LED's. 72 | 73 | 74 | // Initialize changeable global variables. 75 | uint8_t max_bright = 128; // Overall brightness definition. It can be changed on the fly. 76 | 77 | struct CRGB leds[NUM_LEDS]; // Initialize our LED array. 78 | 79 | 80 | 81 | 82 | void setup() { 83 | 84 | Serial.begin(115200); // Initialize serial port for debugging. 85 | delay(1000); // Soft startup to ease the flow of electrons. 86 | 87 | LEDS.addLeds(leds, NUM_LEDS); // Use this for WS2801 or APA102 88 | // LEDS.addLeds(leds, NUM_LEDS); // Use this for WS2812 89 | 90 | FastLED.setBrightness(max_bright); 91 | FastLED.setMaxPowerInVoltsAndMilliamps(5, 500); // FastLED Power management set at 5V, 500mA. 92 | 93 | // Setup the ADC for polled 10 bit sampling on analog pin 5 at 19.2kHz. 94 | cli(); // Disable interrupts. 95 | ADCSRA = 0; // Clear this register. 96 | ADCSRB = 0; // Ditto. 97 | ADMUX = 0; // Ditto. 98 | ADMUX |= (MIC_PIN & 0x07); // Set A5 analog input pin. 99 | ADMUX |= (0 << REFS0); // Set reference voltage (analog reference(external), or using 3.3V microphone on 5V Arduino. 100 | // Set that to 1 if using 5V microphone or 3.3V Arduino. 101 | // ADMUX |= (1 << ADLAR); // Left justify to get 8 bits of data. 102 | ADMUX |= (0 << ADLAR); // Right justify to get full 10 A/D bits. 103 | 104 | // ADCSRA |= bit (ADPS0) | bit (ADPS2); // 32 scaling or 38.5 KHz sampling 105 | ADCSRA |= bit (ADPS1) | bit (ADPS2); // Set ADC clock with 64 prescaler where 16mHz/64=250kHz and 250khz/13 instruction cycles = 19.2khz sampling. 106 | // ADCSRA |= bit (ADPS0) | bit (ADPS1) | bit (ADPS2); // 128 prescaler with 9.6 KHz sampling 107 | 108 | ADCSRA |= (1 << ADPS2) | (1 << ADPS1); // Set ADC clock with 64 prescaler where 16mHz/64=250kHz and 250khz/13 instruction cycles = 19.2khz sampling. 109 | // ADCSRA |= (1 << ADPS2) | (1 << ADPS0); // Set ADC clock with 32 prescaler for 38.5 KHz sampling. 110 | ADCSRA |= (1 << ADATE); // Enable auto trigger. 111 | // ADCSRA |= (1 << ADIE); // Enable interrupts when measurement complete (if using ISR method). Sorry, we're using polling here. 112 | ADCSRA |= (1 << ADEN); // Enable ADC. 113 | ADCSRA |= (1 << ADSC); // Start ADC measurements. 114 | sei(); // Re-enable interrupts. 115 | 116 | } // setup() 117 | 118 | 119 | 120 | void loop() { 121 | 122 | // showfps(); // Debug output of how many frames per second we're getting. Comment this out in production. 123 | getFHT(); // Let's take FHT_N samples and crunch 'em. 124 | fhtDisplay(); // Let's calculate the LED display from our FHT output array. 125 | FastLED.show(); // And then display it. 126 | 127 | } // loop() 128 | 129 | 130 | 131 | void getFHT() { 132 | 133 | get_sound(); // High speed sound sampling. 134 | fht_window(); // Window the data for better frequency response. 135 | fht_reorder(); // Reorder the data before doing the fht. 136 | fht_run(); // Process the data in the fht. 137 | fht_mag_log(); // I guess we'll be converting to logarithm. 138 | // Really, I don't know what these do to tell you the truth. 139 | 140 | } // GetFHT() 141 | 142 | 143 | 144 | void get_sound() { // Uses high speed polled analog sampling and NOT analogRead(). 145 | 146 | // Here's the slow and jittery 8KHz method of sampling sound, which we no longer use. 147 | // for (int i = 0 ; i < FHT_N ; i++) fht_input[i] = analogRead(inputPin) - DC_OFFSET; 148 | 149 | cli(); 150 | for (int i = 0 ; i < FHT_N ; i++) { // Save 256 samples. No more, no less. 151 | while(!(ADCSRA & 0x10)); // Wait for adc to be ready. 152 | ADCSRA = 0xf5; // restart adc 153 | fht_input[i] = ADC - DC_OFFSET; // Get the full 10 bit A/D conversion and center it. 154 | 155 | /* Serial.print(abs(sample)); // Serial plot graph of our sampling. 156 | Serial.print(" "); // Lowest and highest values are graphed so that the plot isn't auto-scaled. 157 | Serial.print(0); // Lowest value 158 | Serial.print(" "); 159 | Serial.print(512); // Highest value 160 | Serial.println(" "); 161 | */ 162 | } 163 | sei(); 164 | 165 | } // get_sound() 166 | 167 | 168 | 169 | void fhtDisplay() { 170 | 171 | #define hueinc 0 // A hue increment value to make it rotate a bit. 172 | #define micmult 10 // Bin values are very low, to let's crank 'em up. 173 | #define noiseval 32 // Increase this to reduce sensitivity. 174 | 175 | for (int i= 0; i < NUM_LEDS; i++) { // Run through the LED array. 176 | int tmp = qsuba(fht_log_out[2*i+2], noiseval); // Get the sample and subtract the 'quiet' normalized values, but don't go < 0. 177 | if (tmp > (leds[i].r + leds[i].g + leds[i].b)) // Refresh an LED only when the intensity is low. By Andrew Tuline. 178 | leds[i] = CHSV(tmp*micmult+hueinc, 255, tmp*micmult); // Note how we really cranked up the tmp value to get BRIGHT LED's. Also increment the hue for fun. 179 | leds[i].nscale8(224); // Let's fade the whole thing over time as well. 180 | } 181 | 182 | } // fhtDisplay() 183 | 184 | 185 | 186 | void showfps() { 187 | 188 | long currentMillis = 0; 189 | static long lastMillis = 0; 190 | static long loops = 0; 191 | 192 | currentMillis=millis(); // Determine frames per second 193 | loops++; 194 | if(currentMillis - lastMillis > 1000){ 195 | Serial.println(loops); 196 | lastMillis = currentMillis; 197 | loops = 0; 198 | } 199 | } // showfps() 200 | -------------------------------------------------------------------------------- /fht_log_ripple/fht_log_ripple.ino: -------------------------------------------------------------------------------- 1 | /* fht_log_ripple 2 | * 3 | * By: Andrew Tuline 4 | * 5 | * Date: January, 2017 6 | * 7 | * Update: March, 2019 (with high speed A/D sampling) 8 | * 9 | * 10 | * This is an example of the FHT library with FastLED for an AVR based Arduino. This uses a Fast Hartley Transform with beat (err, low frequency peak) 11 | * detection for FastLED and displaying a ripple effect. 12 | * 13 | * It does so my converting the input to bins. We then take one of the lowest frequency bins and adjust the peak detection. At least it checks for low frequency. 14 | * 15 | * FHT is available at http://wiki.openmusiclabs.com/wiki/ArduinoFHT 16 | * 17 | * You can use the low frequency peak detector from this sketch to trigger all sort of other routines. 18 | * 19 | * 20 | * Hardware setup: 21 | * 22 | * Arduino Nano & Addressable LED strips 23 | * - Powered by USB power bank 24 | * - APA102 or WS2812 data connected to pin 12. 25 | * - APA102 clock connected to pin 11. 26 | * - 5V on APA102 or WS2812 connected to 5V on Nano (good for short strips). 27 | * - Gnd to Gnd on Nano. 28 | * 29 | * 30 | * Sparkfun MEMS microphone 31 | * - Vcc on microphone is connected to 3.3V on Nano. 32 | * - AREF on Nano connected to 3.3V on Nano. 33 | * - Mic out connected to A5 on Nano. 34 | * - Gnd to Gnd on Nano. 35 | * 36 | * The microphone used for this routine is a Sparkfun ADMP401 MEMS microphone, which runs at 3.3V. With this microphone, we need to tie the AREF pin to 3.3V (if 37 | * using a 5V Arduino UNO/Nano/?. In setup(), you would perform: 38 | * 39 | * analogReference(EXTERNAL); 40 | * 41 | * or use the direct port equivalent, which is: 42 | * 43 | * ADMUX |= (0 << REFS0); 44 | * 45 | * 46 | */ 47 | 48 | 49 | #include "FastLED.h" // FastLED library. Preferably the latest copy of FastLED 2.1. 50 | 51 | // Fixed definitions cannot change on the fly. 52 | #define LED_DT 12 // Data pin to connect to the strip. 53 | #define LED_CK 11 // Clock pin, if using 4 pin strips. 54 | #define COLOR_ORDER BGR // Are they RGB, GRB or what?? 55 | #define LED_TYPE APA102 // What kind of strip are you using? 56 | #define NUM_LEDS 60 // Number of LED's. 57 | 58 | // Initialize changeable global variables. 59 | uint8_t max_bright = 128; // Overall brightness definition. It can be changed on the fly. 60 | 61 | struct CRGB leds[NUM_LEDS]; // Initialize our LED array. 62 | 63 | CRGBPalette16 currentPalette; 64 | CRGBPalette16 targetPalette; 65 | TBlendType currentBlending; // NOBLEND or LINEARBLEND 66 | 67 | // Fast Hartley Transform Definitions 68 | #define LOG_OUT 1 // Use the logarithmic scale. 69 | #define FHT_N 256 // Set to 256 point fht. 70 | #define MIC_PIN 5 // MEMS Microphone input pin. 71 | #define DC_OFFSET 509 // DC offset in mic signal. Should probably be about 512. 72 | #include // FHT library at http://wiki.openmusiclabs.com/wiki/ArduinoFHT 73 | 74 | 75 | // Ripple variables 76 | uint8_t colour; // Ripple colour is randomized and incremented. 77 | int center = 0; // Center of the current ripple. 78 | int step = -1; // -1 is the initializing step. 79 | uint8_t myfade = 255; // Starting brightness. 80 | #define maxsteps 16 // Case statement wouldn't allow a variable. 81 | 82 | unsigned long currentMillis = 0; // Used for timing between detections 83 | unsigned long previousMillis = 0; 84 | unsigned long interval = 60; // 60ms interval seems reasonable 85 | 86 | 87 | 88 | void setup() { 89 | 90 | // analogReference(EXTERNAL); // This is configured in the get_sound routine. In general, you would connect 3.3V to AREF pin for any microphones using 3.3V 91 | 92 | Serial.begin(115200); // Initialize serial port for debugging. 93 | delay(1000); // Soft startup to ease the flow of electrons. 94 | 95 | // LEDS.addLeds(leds, NUM_LEDS); // Use this for WS2812B LED_TYPE 96 | LEDS.addLeds(leds, NUM_LEDS); // Use this for WS2801 or APA102 LED_TYPE 97 | 98 | FastLED.setBrightness(max_bright); 99 | FastLED.setMaxPowerInVoltsAndMilliamps(5, 500); // This is used by the power management functionality and is currently set at 5V, 500mA. 100 | 101 | currentPalette = PartyColors_p; // Nice bright starting colours. 102 | currentBlending = LINEARBLEND; 103 | 104 | // Setup the ADC for polled 10 bit sampling on analog pin 5 at 19.2kHz. 105 | cli(); // Disable interrupts. 106 | ADCSRA = 0; // Clear this register. 107 | ADCSRB = 0; // Ditto. 108 | ADMUX = 0; // Ditto. 109 | ADMUX |= (MIC_PIN & 0x07); // Set A5 analog input pin. 110 | ADMUX |= (0 << REFS0); // Set reference voltage (analog reference(external), or using 3.3V microphone on 5V Arduino. 111 | // Set that to 1 if using 5V microphone or 3.3V Arduino. 112 | // ADMUX |= (1 << ADLAR); // Left justify to get 8 bits of data. 113 | ADMUX |= (0 << ADLAR); // Right justify to get full 10 A/D bits. 114 | 115 | // ADCSRA |= bit (ADPS0) | bit (ADPS2); // 32 scaling or 38.5 KHz sampling 116 | // ADCSRA |= bit (ADPS1) | bit (ADPS2); // Set ADC clock with 64 prescaler where 16mHz/64=250kHz and 250khz/13 instruction cycles = 19.2khz sampling. 117 | ADCSRA |= bit (ADPS0) | bit (ADPS1) | bit (ADPS2); // 128 prescaler with 9.6 KHz sampling 118 | 119 | 120 | ADCSRA |= (1 << ADATE); // Enable auto trigger. 121 | // ADCSRA |= (1 << ADIE); // Enable interrupts when measurement complete (if using ISR method). Sorry, we're using polling here. 122 | ADCSRA |= (1 << ADEN); // Enable ADC. 123 | ADCSRA |= (1 << ADSC); // Start ADC measurements. 124 | sei(); // Re-enable interrupts. 125 | 126 | } // setup() 127 | 128 | 129 | 130 | void loop() { 131 | 132 | EVERY_N_MILLISECONDS(100) { 133 | uint8_t maxChanges = 24; 134 | nblendPaletteTowardPalette(currentPalette, targetPalette, maxChanges); // AWESOME palette blending capability. 135 | } 136 | 137 | EVERY_N_SECONDS(5) { // Change the target palette to a random one every 5 seconds. 138 | targetPalette = CRGBPalette16(CHSV(random8(), 255, random8(128,255)), CHSV(random8(), 255, random8(128,255)), CHSV(random8(), 192, random8(128,255)), CHSV(random8(), 255, random8(128,255))); 139 | } 140 | 141 | GetFHT(); // Sample the input and generate an FHT table 142 | isripple(); // Is there a low frequency peak detected? If so, trigger a new ripple. 143 | ripple(); // Let's cycle through the ripple routine. 144 | 145 | FastLED.show(); // Run the FastLED.show() at full loop speed. 146 | 147 | } // loop() 148 | 149 | 150 | 151 | void GetFHT() { 152 | 153 | get_sound(); // High speed sample of sound which is input into the FHT array. 154 | fht_window(); // Window the data for better frequency response. 155 | fht_reorder(); // Reorder the data before doing the fht. 156 | fht_run(); // Process the data in the fht. 157 | fht_mag_log(); // Let's use logarithmic bins. 158 | 159 | } // GetFHT() 160 | 161 | 162 | 163 | void get_sound() { // Uses high speed polled analog sampling and NOT analogRead(). 164 | 165 | cli(); // Disable interrupts for the duration of the sampling. 166 | for (int i = 0 ; i < FHT_N ; i++) { // Save 256 samples. No more, no less. 167 | while(!(ADCSRA & 0x10)); // Wait for adc to be ready. 168 | ADCSRA = 0xf5; // Restart adc 169 | fht_input[i] = ADC - DC_OFFSET; // Get the full 10 bit A/D conversion and center it. 170 | } 171 | sei(); // Re-enable interrupts. 172 | 173 | } // get_sound() 174 | 175 | 176 | 177 | void isripple() { 178 | 179 | uint8_t noiseval = 32; // Our detection value. 180 | 181 | // noiseval = map(analogRead(potPin), 0, 1023, 16, 96); // Read potentiometer and map for sensitivity. Removed. 182 | 183 | currentMillis = millis(); 184 | if (currentMillis - previousMillis >= interval) { // Wait for interval ms before allowing a new ripple to be generated. 185 | previousMillis = currentMillis; 186 | if (abs(fht_log_out[3]) - noiseval > 0) step = -1; // If the low frequency sound > threshold then start a ripple. 187 | } 188 | 189 | } // isripple() 190 | 191 | 192 | 193 | void ripple() { 194 | 195 | fadeToBlackBy(leds, NUM_LEDS, 64); // 8 bit, 1 = slow, 255 = fast 196 | 197 | switch (step) { 198 | 199 | case -1: // Initialize ripple variables. 200 | center = random(NUM_LEDS); 201 | step = 0; 202 | break; 203 | 204 | case 0: 205 | leds[center] = ColorFromPalette(currentPalette, colour, 255, currentBlending); // Display the first pixel of the ripple. 206 | step ++; 207 | break; 208 | 209 | case maxsteps: // At the end of the ripples. 210 | // step = -1; 211 | break; 212 | 213 | default: // Middle of the ripples. 214 | leds[(center + step + NUM_LEDS) % NUM_LEDS] += ColorFromPalette( currentPalette, colour, myfade/step, currentBlending); // Simple wrap from Marc Miller 215 | leds[(center - step + NUM_LEDS) % NUM_LEDS] += ColorFromPalette( currentPalette, colour, myfade/step, currentBlending); 216 | 217 | step ++; // Next step. 218 | 219 | break; 220 | 221 | } // switch step 222 | 223 | colour+=2; // Rotate the palette colour. 224 | 225 | } // ripple() 226 | 227 | -------------------------------------------------------------------------------- /notasound/besin.h: -------------------------------------------------------------------------------- 1 | #ifndef BESIN_H 2 | #define BESIN_H 3 | 4 | void besin() { // Add a Perlin noise soundbar. This looks really cool. 5 | // Shows you don't need a crap ton of code for a cool effect. 6 | // Local definitions 7 | 8 | // Persistent local variables 9 | 10 | // Temporary local variables 11 | 12 | 13 | leds[NUM_LEDS/2] = ColorFromPalette(currentPalette, millis(), sampleAgc, NOBLEND); 14 | leds[NUM_LEDS/2-1] = ColorFromPalette(currentPalette, millis(), sampleAgc, NOBLEND); 15 | 16 | waveit(); // Move the pixels to the left/right, but not too fast. 17 | 18 | fadeToBlackBy(leds, NUM_LEDS, 2); // Fade the center, while waveit moves everything out to the edges. 19 | 20 | } // besin() 21 | 22 | #endif 23 | -------------------------------------------------------------------------------- /notasound/commands.h: -------------------------------------------------------------------------------- 1 | #ifndef COMMANDS_H 2 | #define COMMANDS_H 3 | 4 | 5 | // This maps 24 IR key locations to the digital output of each key. Edit to match your controller. 6 | // I have another almost identical 24 button controller, and it has different commands. 7 | 8 | #define IR_ADD 61184 9 | 10 | #define IR_A1 0 11 | #define IR_A2 1 12 | #define IR_A3 2 13 | #define IR_A4 3 14 | 15 | #define IR_B1 4 16 | #define IR_B2 5 17 | #define IR_B3 6 18 | #define IR_B4 7 19 | 20 | #define IR_C1 8 21 | #define IR_C2 9 22 | #define IR_C3 10 23 | #define IR_C4 11 24 | 25 | #define IR_D1 12 26 | #define IR_D2 13 27 | #define IR_D3 14 28 | #define IR_D4 15 29 | 30 | #define IR_E1 16 31 | #define IR_E2 17 32 | #define IR_E3 18 33 | #define IR_E4 19 34 | 35 | #define IR_F1 20 36 | #define IR_F2 21 37 | #define IR_F3 22 38 | #define IR_F4 23 39 | 40 | 41 | /* 42 | 43 | // Here's the other controller 44 | 45 | #define IR_ADD 65280 46 | 47 | #define IR_A1 9 48 | #define IR_A2 29 49 | #define IR_A3 31 50 | #define IR_A4 13 51 | 52 | #define IR_B1 25 53 | #define IR_B2 27 54 | #define IR_B3 17 55 | #define IR_B4 21 56 | 57 | #define IR_C1 23 58 | #define IR_C2 18 59 | #define IR_C3 22 60 | #define IR_C4 77 61 | 62 | #define IR_D1 64 63 | #define IR_D2 76 64 | #define IR_D3 4 65 | #define IR_D4 0 66 | 67 | #define IR_E1 10 68 | #define IR_E2 30 69 | #define IR_E3 14 70 | #define IR_E4 26 71 | 72 | #define IR_F1 28 73 | #define IR_F2 20 74 | #define IR_F3 15 75 | #define IR_F4 12 76 | 77 | */ 78 | 79 | 80 | #endif 81 | -------------------------------------------------------------------------------- /notasound/fillnoise.h: -------------------------------------------------------------------------------- 1 | #ifndef FILLNOISE_H 2 | #define FILLNOISE_H 3 | 4 | void fillnoise() { // Another perlin noise based routine. 5 | 6 | // Local definitions 7 | #define xscale 160 8 | #define yscale 160 9 | 10 | // Persistent local variables 11 | static int16_t xdist; // A random number for our noise generator. 12 | static int16_t ydist; 13 | 14 | // Temporary local variables 15 | 16 | 17 | 18 | if (sampleAvg > NUM_LEDS) sampleAvg = NUM_LEDS; // Clip the sampleAvg to maximize at NUM_LEDS. 19 | 20 | for (int i= (NUM_LEDS-sampleAvg/2)/2; i<(NUM_LEDS+sampleAvg/2)/2; i++) { // The louder the sound, the wider the soundbar. 21 | uint8_t index = inoise8(i*sampleAvg+xdist, ydist+i*sampleAvg); // Get a value from the noise function. I'm using both x and y axis. 22 | 23 | leds[i] = ColorFromPalette(currentPalette, index, sampleAgc, LINEARBLEND); // With that value, look up the 8 bit colour palette value and assign it to the current LED. 24 | } // Effect is a NOISE bar the width of sampleAvg. Very fun. By Andrew Tuline. 25 | 26 | xdist += beatsin8(5,0,3); // Moving forward in the NOISE field, but with a sine motion. 27 | ydist += beatsin8(4,0,3); // Moving sideways in the NOISE field, but with a sine motion. 28 | 29 | waveit(); // Move the pixels to the left/right, but not too fast. 30 | 31 | fadeToBlackBy(leds+NUM_LEDS/2-1, 2, 64); // Fade the center, while waveit moves everything out to the edges. 32 | 33 | } // fillnoise() 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /notasound/fire.h: -------------------------------------------------------------------------------- 1 | #ifndef FIRE_H 2 | #define FIRE_H 3 | 4 | void fire() { // Create fire based on noise and sampleAvg. 5 | 6 | // Local definitions 7 | #define xscale 20 // How far apart they are 8 | #define yscale 3 // How fast they move 9 | 10 | // Persistent local variables 11 | 12 | // Temporary local variables 13 | uint16_t index = 0; // Current colour lookup value. 14 | 15 | 16 | currentPalette = CRGBPalette16(CHSV(0,255,2), CHSV(0,255,4), CHSV(0,255,8), CHSV(0, 255, 8), // Fire palette definition. Lower value = darker. 17 | CHSV(0, 255, 16), CRGB::Red, CRGB::Red, CRGB::Red, 18 | CRGB::DarkOrange,CRGB::DarkOrange, CRGB::Orange, CRGB::Orange, 19 | CRGB::Yellow, CRGB::Orange, CRGB::Yellow, CRGB::Yellow); 20 | 21 | for(int i = 0; i < NUM_LEDS; i++) { 22 | 23 | index = inoise8(i*xscale,millis()*yscale*NUM_LEDS/255); // X location is constant, but we move along the Y at the rate of millis(). By Andrew Tuline. 24 | 25 | index = (255 - i*256/NUM_LEDS) * index/128; // Now we need to scale index so that it gets blacker as we get close to one of the ends. 26 | // This is a simple y=mx+b equation that's been scaled. index/128 is another scaling. 27 | leds[i] = ColorFromPalette(currentPalette, index, sampleAvg, NOBLEND); // With that value, look up the 8 bit colour palette value and assign it to the current LED. 28 | } // The higher the value of i => the higher up the palette index (see palette definition). 29 | 30 | } // fire() 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /notasound/firewide.h: -------------------------------------------------------------------------------- 1 | #ifndef FIREWIDE_H 2 | #define FIREWIDE_H 3 | 4 | void firewide() { // Create fire based on noise and sampleAvg. 5 | 6 | // Local definitions 7 | #define xscale 20 // How far apart they are 8 | #define yscale 3 // How fast they move 9 | 10 | // Persistent local variables 11 | 12 | // Temporary local variables 13 | uint16_t index = 0; // Current colour lookup value. 14 | 15 | 16 | currentPalette = CRGBPalette16(CHSV(0,255,2), CHSV(0,255,4), CHSV(0,255,6), CHSV(0, 255, 8), // Fire palette definition. Lower value = darker. 17 | CHSV(0, 255, 16), CRGB::Red, CRGB::Red, CRGB::Red, 18 | CRGB::DarkOrange,CRGB::DarkOrange, CRGB::Orange, CRGB::Orange, 19 | CRGB::Yellow, CRGB::Orange, CRGB::Yellow, CRGB::Yellow); 20 | 21 | for(int i = 0; i < NUM_LEDS; i++) { 22 | 23 | index = inoise8(i*xscale,millis()*yscale*NUM_LEDS/255); // X location is constant, but we move along the Y at the rate of millis(). By Andrew Tuline. 24 | 25 | index = (255 - i*256/NUM_LEDS) * index / 128; // Now we need to scale index so that it gets blacker as we get close to one of the ends 26 | 27 | leds[NUM_LEDS/2-i/2+1] = ColorFromPalette(currentPalette, index, sampleAvg*4, NOBLEND); // With that value, look up the 8 bit colour palette value and assign it to the current LED. 28 | leds[NUM_LEDS/2+i/2-1] = ColorFromPalette(currentPalette, index, sampleAvg*4, NOBLEND); // With that value, look up the 8 bit colour palette value and assign it to the current LED. 29 | 30 | } // The higher the value of i => the higher up the palette index (see palette definition). 31 | 32 | } // firewide() 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /notasound/getsample.h: -------------------------------------------------------------------------------- 1 | #ifndef GETSAMPLE_H 2 | #define GETSAMPLE_H 3 | 4 | void getSample() { 5 | 6 | int16_t micIn; // Current sample starts with negative values and large values, which is why it's 16 bit signed. 7 | static long peakTime; 8 | 9 | micIn = analogRead(MIC_PIN); // Poor man's analog Read. 10 | micLev = ((micLev * 31) + micIn) / 32; // Smooth it out over the last 32 samples for automatic centering. Needs to be a float. 11 | micIn -= micLev; // Let's center it to 0 now. 12 | micIn = abs(micIn); // And get the absolute value of each sample. 13 | sample = (micIn <= squelch) ? 0 : (sample + micIn)/2; // Using a ternary operator, the resultant sample is either 0 or it's a bit smoothed out with the last sample. 14 | sampleAvg = ((sampleAvg * 31) + sample) / 32; // Smooth it out over the last 32 samples. 15 | 16 | if (sample > (sampleAvg+maxVol) && millis() > (peakTime + 50)) { // Poor man's beat detection by seeing if sample > Average + some value. 17 | samplePeak = 1; 18 | peakTime=millis(); 19 | } // Then we got a peak, else we don't. Display routines need to reset the samplepeak value in case they miss the trigger. 20 | 21 | } // getSample() 22 | 23 | 24 | 25 | void agcAvg() { // A simple averaging multiplier to automatically adjust sound sensitivity. 26 | 27 | multAgc = (sampleAvg < 1) ? targetAgc : targetAgc / sampleAvg; // Make the multiplier so that sampleAvg * multiplier = setpoint 28 | sampleAgc = sample * multAgc; 29 | if (sampleAgc > 255) sampleAgc = 255; 30 | 31 | //------------ Oscilloscope output --------------------------- 32 | // Serial.print(targetAgc); Serial.print(" "); 33 | // Serial.print(multAgc); Serial.print(" "); 34 | // Serial.print(sampleAgc); Serial.print(" "); 35 | 36 | // Serial.print(sample); Serial.print(" "); 37 | // Serial.print(sampleAvg); Serial.print(" "); 38 | // Serial.print(micLev); Serial.print(" "); 39 | // Serial.print(samplePeak); Serial.print(" "); samplePeak = 0; 40 | // Serial.print(100); Serial.print(" "); 41 | // Serial.print(0); Serial.print(" "); 42 | // Serial.println(" "); 43 | 44 | } // agcAvg() 45 | 46 | #endif 47 | -------------------------------------------------------------------------------- /notasound/gradient_palettes.h: -------------------------------------------------------------------------------- 1 | #ifndef GRADIENT_PALETTES_H 2 | #define GRADIENT_PALETTES_H 3 | 4 | // From ColorWavesWithPalettes by Mark Kriegsman: https://gist.github.com/kriegsman/8281905786e8b2632aeb 5 | 6 | // Gradient Color Palette definitions for 33 different cpt-city color palettes. 7 | // 956 bytes of PROGMEM for all of the palettes together, 8 | // +618 bytes of PROGMEM for gradient palette code (AVR). 9 | // 1,494 bytes total for all 34 color palettes and associated code. 10 | 11 | // Gradient palette "ib_jul01_gp", originally from 12 | // http://soliton.vm.bytemark.co.uk/pub/cpt-city/ing/xmas/tn/ib_jul01.png.index.html 13 | // converted for FastLED with gammas (2.6, 2.2, 2.5) 14 | // Size: 16 bytes of program space. 15 | 16 | DEFINE_GRADIENT_PALETTE( ib_jul01_gp ) { 17 | 0, 194, 1, 1, 18 | 94, 1, 29, 18, 19 | 132, 57,131, 28, 20 | 255, 113, 1, 1}; 21 | 22 | // Gradient palette "es_vintage_57_gp", originally from 23 | // http://soliton.vm.bytemark.co.uk/pub/cpt-city/es/vintage/tn/es_vintage_57.png.index.html 24 | // converted for FastLED with gammas (2.6, 2.2, 2.5) 25 | // Size: 20 bytes of program space. 26 | 27 | DEFINE_GRADIENT_PALETTE( es_vintage_57_gp ) { 28 | 0, 2, 1, 1, 29 | 53, 18, 1, 0, 30 | 104, 69, 29, 1, 31 | 153, 167,135, 10, 32 | 255, 46, 56, 4}; 33 | 34 | // Gradient palette "es_vintage_01_gp", originally from 35 | // http://soliton.vm.bytemark.co.uk/pub/cpt-city/es/vintage/tn/es_vintage_01.png.index.html 36 | // converted for FastLED with gammas (2.6, 2.2, 2.5) 37 | // Size: 32 bytes of program space. 38 | 39 | DEFINE_GRADIENT_PALETTE( es_vintage_01_gp ) { 40 | 0, 4, 1, 1, 41 | 51, 16, 0, 1, 42 | 76, 97,104, 3, 43 | 101, 255,131, 19, 44 | 127, 67, 9, 4, 45 | 153, 16, 0, 1, 46 | 229, 4, 1, 1, 47 | 255, 4, 1, 1}; 48 | 49 | // Gradient palette "es_rivendell_15_gp", originally from 50 | // http://soliton.vm.bytemark.co.uk/pub/cpt-city/es/rivendell/tn/es_rivendell_15.png.index.html 51 | // converted for FastLED with gammas (2.6, 2.2, 2.5) 52 | // Size: 20 bytes of program space. 53 | 54 | DEFINE_GRADIENT_PALETTE( es_rivendell_15_gp ) { 55 | 0, 1, 14, 5, 56 | 101, 16, 36, 14, 57 | 165, 56, 68, 30, 58 | 242, 150,156, 99, 59 | 255, 150,156, 99}; 60 | 61 | // Gradient palette "rgi_15_gp", originally from 62 | // http://soliton.vm.bytemark.co.uk/pub/cpt-city/ds/rgi/tn/rgi_15.png.index.html 63 | // converted for FastLED with gammas (2.6, 2.2, 2.5) 64 | // Size: 36 bytes of program space. 65 | 66 | DEFINE_GRADIENT_PALETTE( rgi_15_gp ) { 67 | 0, 4, 1, 31, 68 | 31, 55, 1, 16, 69 | 63, 197, 3, 7, 70 | 95, 59, 2, 17, 71 | 127, 6, 2, 34, 72 | 159, 39, 6, 33, 73 | 191, 112, 13, 32, 74 | 223, 56, 9, 35, 75 | 255, 22, 6, 38}; 76 | 77 | // Gradient palette "retro2_16_gp", originally from 78 | // http://soliton.vm.bytemark.co.uk/pub/cpt-city/ma/retro2/tn/retro2_16.png.index.html 79 | // converted for FastLED with gammas (2.6, 2.2, 2.5) 80 | // Size: 8 bytes of program space. 81 | 82 | DEFINE_GRADIENT_PALETTE( retro2_16_gp ) { 83 | 0, 188,135, 1, 84 | 255, 46, 7, 1}; 85 | 86 | // Gradient palette "Analogous_1_gp", originally from 87 | // http://soliton.vm.bytemark.co.uk/pub/cpt-city/nd/red/tn/Analogous_1.png.index.html 88 | // converted for FastLED with gammas (2.6, 2.2, 2.5) 89 | // Size: 20 bytes of program space. 90 | 91 | DEFINE_GRADIENT_PALETTE( Analogous_1_gp ) { 92 | 0, 3, 0,255, 93 | 63, 23, 0,255, 94 | 127, 67, 0,255, 95 | 191, 142, 0, 45, 96 | 255, 255, 0, 0}; 97 | 98 | // Gradient palette "es_pinksplash_08_gp", originally from 99 | // http://soliton.vm.bytemark.co.uk/pub/cpt-city/es/pink_splash/tn/es_pinksplash_08.png.index.html 100 | // converted for FastLED with gammas (2.6, 2.2, 2.5) 101 | // Size: 20 bytes of program space. 102 | 103 | DEFINE_GRADIENT_PALETTE( es_pinksplash_08_gp ) { 104 | 0, 126, 11,255, 105 | 127, 197, 1, 22, 106 | 175, 210,157,172, 107 | 221, 157, 3,112, 108 | 255, 157, 3,112}; 109 | 110 | // Gradient palette "es_pinksplash_07_gp", originally from 111 | // http://soliton.vm.bytemark.co.uk/pub/cpt-city/es/pink_splash/tn/es_pinksplash_07.png.index.html 112 | // converted for FastLED with gammas (2.6, 2.2, 2.5) 113 | // Size: 28 bytes of program space. 114 | 115 | DEFINE_GRADIENT_PALETTE( es_pinksplash_07_gp ) { 116 | 0, 229, 1, 1, 117 | 61, 242, 4, 63, 118 | 101, 255, 12,255, 119 | 127, 249, 81,252, 120 | 153, 255, 11,235, 121 | 193, 244, 5, 68, 122 | 255, 232, 1, 5}; 123 | 124 | // Gradient palette "Coral_reef_gp", originally from 125 | // http://soliton.vm.bytemark.co.uk/pub/cpt-city/nd/other/tn/Coral_reef.png.index.html 126 | // converted for FastLED with gammas (2.6, 2.2, 2.5) 127 | // Size: 24 bytes of program space. 128 | 129 | DEFINE_GRADIENT_PALETTE( Coral_reef_gp ) { 130 | 0, 40,199,197, 131 | 50, 10,152,155, 132 | 96, 1,111,120, 133 | 96, 43,127,162, 134 | 139, 10, 73,111, 135 | 255, 1, 34, 71}; 136 | 137 | // Gradient palette "es_ocean_breeze_068_gp", originally from 138 | // http://soliton.vm.bytemark.co.uk/pub/cpt-city/es/ocean_breeze/tn/es_ocean_breeze_068.png.index.html 139 | // converted for FastLED with gammas (2.6, 2.2, 2.5) 140 | // Size: 24 bytes of program space. 141 | 142 | DEFINE_GRADIENT_PALETTE( es_ocean_breeze_068_gp ) { 143 | 0, 100,156,153, 144 | 51, 1, 99,137, 145 | 101, 1, 68, 84, 146 | 104, 35,142,168, 147 | 178, 0, 63,117, 148 | 255, 1, 10, 10}; 149 | 150 | // Gradient palette "es_ocean_breeze_036_gp", originally from 151 | // http://soliton.vm.bytemark.co.uk/pub/cpt-city/es/ocean_breeze/tn/es_ocean_breeze_036.png.index.html 152 | // converted for FastLED with gammas (2.6, 2.2, 2.5) 153 | // Size: 16 bytes of program space. 154 | 155 | DEFINE_GRADIENT_PALETTE( es_ocean_breeze_036_gp ) { 156 | 0, 1, 6, 7, 157 | 89, 1, 99,111, 158 | 153, 144,209,255, 159 | 255, 0, 73, 82}; 160 | 161 | // Gradient palette "departure_gp", originally from 162 | // http://soliton.vm.bytemark.co.uk/pub/cpt-city/mjf/tn/departure.png.index.html 163 | // converted for FastLED with gammas (2.6, 2.2, 2.5) 164 | // Size: 88 bytes of program space. 165 | 166 | DEFINE_GRADIENT_PALETTE( departure_gp ) { 167 | 0, 8, 3, 0, 168 | 42, 23, 7, 0, 169 | 63, 75, 38, 6, 170 | 84, 169, 99, 38, 171 | 106, 213,169,119, 172 | 116, 255,255,255, 173 | 138, 135,255,138, 174 | 148, 22,255, 24, 175 | 170, 0,255, 0, 176 | 191, 0,136, 0, 177 | 212, 0, 55, 0, 178 | 255, 0, 55, 0}; 179 | 180 | // Gradient palette "es_landscape_64_gp", originally from 181 | // http://soliton.vm.bytemark.co.uk/pub/cpt-city/es/landscape/tn/es_landscape_64.png.index.html 182 | // converted for FastLED with gammas (2.6, 2.2, 2.5) 183 | // Size: 36 bytes of program space. 184 | 185 | DEFINE_GRADIENT_PALETTE( es_landscape_64_gp ) { 186 | 0, 0, 0, 0, 187 | 37, 2, 25, 1, 188 | 76, 15,115, 5, 189 | 127, 79,213, 1, 190 | 128, 126,211, 47, 191 | 130, 188,209,247, 192 | 153, 144,182,205, 193 | 204, 59,117,250, 194 | 255, 1, 37,192}; 195 | 196 | // Gradient palette "es_landscape_33_gp", originally from 197 | // http://soliton.vm.bytemark.co.uk/pub/cpt-city/es/landscape/tn/es_landscape_33.png.index.html 198 | // converted for FastLED with gammas (2.6, 2.2, 2.5) 199 | // Size: 24 bytes of program space. 200 | 201 | DEFINE_GRADIENT_PALETTE( es_landscape_33_gp ) { 202 | 0, 1, 5, 0, 203 | 19, 32, 23, 1, 204 | 38, 161, 55, 1, 205 | 63, 229,144, 1, 206 | 66, 39,142, 74, 207 | 255, 1, 4, 1}; 208 | 209 | // Gradient palette "rainbowsherbet_gp", originally from 210 | // http://soliton.vm.bytemark.co.uk/pub/cpt-city/ma/icecream/tn/rainbowsherbet.png.index.html 211 | // converted for FastLED with gammas (2.6, 2.2, 2.5) 212 | // Size: 28 bytes of program space. 213 | 214 | DEFINE_GRADIENT_PALETTE( rainbowsherbet_gp ) { 215 | 0, 255, 33, 4, 216 | 43, 255, 68, 25, 217 | 86, 255, 7, 25, 218 | 127, 255, 82,103, 219 | 170, 255,255,242, 220 | 209, 42,255, 22, 221 | 255, 87,255, 65}; 222 | 223 | // Gradient palette "gr65_hult_gp", originally from 224 | // http://soliton.vm.bytemark.co.uk/pub/cpt-city/hult/tn/gr65_hult.png.index.html 225 | // converted for FastLED with gammas (2.6, 2.2, 2.5) 226 | // Size: 24 bytes of program space. 227 | 228 | DEFINE_GRADIENT_PALETTE( gr65_hult_gp ) { 229 | 0, 247,176,247, 230 | 48, 255,136,255, 231 | 89, 220, 29,226, 232 | 160, 7, 82,178, 233 | 216, 1,124,109, 234 | 255, 1,124,109}; 235 | 236 | // Gradient palette "gr64_hult_gp", originally from 237 | // http://soliton.vm.bytemark.co.uk/pub/cpt-city/hult/tn/gr64_hult.png.index.html 238 | // converted for FastLED with gammas (2.6, 2.2, 2.5) 239 | // Size: 32 bytes of program space. 240 | 241 | DEFINE_GRADIENT_PALETTE( gr64_hult_gp ) { 242 | 0, 1,124,109, 243 | 66, 1, 93, 79, 244 | 104, 52, 65, 1, 245 | 130, 115,127, 1, 246 | 150, 52, 65, 1, 247 | 201, 1, 86, 72, 248 | 239, 0, 55, 45, 249 | 255, 0, 55, 45}; 250 | 251 | // Gradient palette "GMT_drywet_gp", originally from 252 | // http://soliton.vm.bytemark.co.uk/pub/cpt-city/gmt/tn/GMT_drywet.png.index.html 253 | // converted for FastLED with gammas (2.6, 2.2, 2.5) 254 | // Size: 28 bytes of program space. 255 | 256 | DEFINE_GRADIENT_PALETTE( GMT_drywet_gp ) { 257 | 0, 47, 30, 2, 258 | 42, 213,147, 24, 259 | 84, 103,219, 52, 260 | 127, 3,219,207, 261 | 170, 1, 48,214, 262 | 212, 1, 1,111, 263 | 255, 1, 7, 33}; 264 | 265 | // Gradient palette "ib15_gp", originally from 266 | // http://soliton.vm.bytemark.co.uk/pub/cpt-city/ing/general/tn/ib15.png.index.html 267 | // converted for FastLED with gammas (2.6, 2.2, 2.5) 268 | // Size: 24 bytes of program space. 269 | 270 | DEFINE_GRADIENT_PALETTE( ib15_gp ) { 271 | 0, 113, 91,147, 272 | 72, 157, 88, 78, 273 | 89, 208, 85, 33, 274 | 107, 255, 29, 11, 275 | 141, 137, 31, 39, 276 | 255, 59, 33, 89}; 277 | 278 | // Gradient palette "Fuschia_7_gp", originally from 279 | // http://soliton.vm.bytemark.co.uk/pub/cpt-city/ds/fuschia/tn/Fuschia-7.png.index.html 280 | // converted for FastLED with gammas (2.6, 2.2, 2.5) 281 | // Size: 20 bytes of program space. 282 | 283 | DEFINE_GRADIENT_PALETTE( Fuschia_7_gp ) { 284 | 0, 43, 3,153, 285 | 63, 100, 4,103, 286 | 127, 188, 5, 66, 287 | 191, 161, 11,115, 288 | 255, 135, 20,182}; 289 | 290 | // Gradient palette "es_emerald_dragon_08_gp", originally from 291 | // http://soliton.vm.bytemark.co.uk/pub/cpt-city/es/emerald_dragon/tn/es_emerald_dragon_08.png.index.html 292 | // converted for FastLED with gammas (2.6, 2.2, 2.5) 293 | // Size: 16 bytes of program space. 294 | 295 | DEFINE_GRADIENT_PALETTE( es_emerald_dragon_08_gp ) { 296 | 0, 97,255, 1, 297 | 101, 47,133, 1, 298 | 178, 13, 43, 1, 299 | 255, 2, 10, 1}; 300 | 301 | // Gradient palette "lava_gp", originally from 302 | // http://soliton.vm.bytemark.co.uk/pub/cpt-city/neota/elem/tn/lava.png.index.html 303 | // converted for FastLED with gammas (2.6, 2.2, 2.5) 304 | // Size: 52 bytes of program space. 305 | 306 | DEFINE_GRADIENT_PALETTE( lava_gp ) { 307 | 0, 0, 0, 0, 308 | 46, 18, 0, 0, 309 | 96, 113, 0, 0, 310 | 108, 142, 3, 1, 311 | 119, 175, 17, 1, 312 | 146, 213, 44, 2, 313 | 174, 255, 82, 4, 314 | 188, 255,115, 4, 315 | 202, 255,156, 4, 316 | 218, 255,203, 4, 317 | 234, 255,255, 4, 318 | 244, 255,255, 71, 319 | 255, 255,255,255}; 320 | 321 | // Gradient palette "fire_gp", originally from 322 | // http://soliton.vm.bytemark.co.uk/pub/cpt-city/neota/elem/tn/fire.png.index.html 323 | // converted for FastLED with gammas (2.6, 2.2, 2.5) 324 | // Size: 28 bytes of program space. 325 | 326 | DEFINE_GRADIENT_PALETTE( fire_gp ) { 327 | 0, 1, 1, 0, 328 | 76, 32, 5, 0, 329 | 146, 192, 24, 0, 330 | 197, 220,105, 5, 331 | 240, 252,255, 31, 332 | 250, 252,255,111, 333 | 255, 255,255,255}; 334 | 335 | // Gradient palette "Colorfull_gp", originally from 336 | // http://soliton.vm.bytemark.co.uk/pub/cpt-city/nd/atmospheric/tn/Colorfull.png.index.html 337 | // converted for FastLED with gammas (2.6, 2.2, 2.5) 338 | // Size: 44 bytes of program space. 339 | 340 | DEFINE_GRADIENT_PALETTE( Colorfull_gp ) { 341 | 0, 10, 85, 5, 342 | 25, 29,109, 18, 343 | 60, 59,138, 42, 344 | 93, 83, 99, 52, 345 | 106, 110, 66, 64, 346 | 109, 123, 49, 65, 347 | 113, 139, 35, 66, 348 | 116, 192,117, 98, 349 | 124, 255,255,137, 350 | 168, 100,180,155, 351 | 255, 22,121,174}; 352 | 353 | // Gradient palette "Magenta_Evening_gp", originally from 354 | // http://soliton.vm.bytemark.co.uk/pub/cpt-city/nd/atmospheric/tn/Magenta_Evening.png.index.html 355 | // converted for FastLED with gammas (2.6, 2.2, 2.5) 356 | // Size: 28 bytes of program space. 357 | 358 | DEFINE_GRADIENT_PALETTE( Magenta_Evening_gp ) { 359 | 0, 71, 27, 39, 360 | 31, 130, 11, 51, 361 | 63, 213, 2, 64, 362 | 70, 232, 1, 66, 363 | 76, 252, 1, 69, 364 | 108, 123, 2, 51, 365 | 255, 46, 9, 35}; 366 | 367 | // Gradient palette "Pink_Purple_gp", originally from 368 | // http://soliton.vm.bytemark.co.uk/pub/cpt-city/nd/atmospheric/tn/Pink_Purple.png.index.html 369 | // converted for FastLED with gammas (2.6, 2.2, 2.5) 370 | // Size: 44 bytes of program space. 371 | 372 | DEFINE_GRADIENT_PALETTE( Pink_Purple_gp ) { 373 | 0, 19, 2, 39, 374 | 25, 26, 4, 45, 375 | 51, 33, 6, 52, 376 | 76, 68, 62,125, 377 | 102, 118,187,240, 378 | 109, 163,215,247, 379 | 114, 217,244,255, 380 | 122, 159,149,221, 381 | 149, 113, 78,188, 382 | 183, 128, 57,155, 383 | 255, 146, 40,123}; 384 | 385 | // Gradient palette "Sunset_Real_gp", originally from 386 | // http://soliton.vm.bytemark.co.uk/pub/cpt-city/nd/atmospheric/tn/Sunset_Real.png.index.html 387 | // converted for FastLED with gammas (2.6, 2.2, 2.5) 388 | // Size: 28 bytes of program space. 389 | 390 | DEFINE_GRADIENT_PALETTE( Sunset_Real_gp ) { 391 | 0, 120, 0, 0, 392 | 22, 179, 22, 0, 393 | 51, 255,104, 0, 394 | 85, 167, 22, 18, 395 | 135, 100, 0,103, 396 | 198, 16, 0,130, 397 | 255, 0, 0,160}; 398 | 399 | // Gradient palette "es_autumn_19_gp", originally from 400 | // http://soliton.vm.bytemark.co.uk/pub/cpt-city/es/autumn/tn/es_autumn_19.png.index.html 401 | // converted for FastLED with gammas (2.6, 2.2, 2.5) 402 | // Size: 52 bytes of program space. 403 | 404 | DEFINE_GRADIENT_PALETTE( es_autumn_19_gp ) { 405 | 0, 26, 1, 1, 406 | 51, 67, 4, 1, 407 | 84, 118, 14, 1, 408 | 104, 137,152, 52, 409 | 112, 113, 65, 1, 410 | 122, 133,149, 59, 411 | 124, 137,152, 52, 412 | 135, 113, 65, 1, 413 | 142, 139,154, 46, 414 | 163, 113, 13, 1, 415 | 204, 55, 3, 1, 416 | 249, 17, 1, 1, 417 | 255, 17, 1, 1}; 418 | 419 | // Gradient palette "BlacK_Blue_Magenta_White_gp", originally from 420 | // http://soliton.vm.bytemark.co.uk/pub/cpt-city/nd/basic/tn/BlacK_Blue_Magenta_White.png.index.html 421 | // converted for FastLED with gammas (2.6, 2.2, 2.5) 422 | // Size: 28 bytes of program space. 423 | 424 | DEFINE_GRADIENT_PALETTE( BlacK_Blue_Magenta_White_gp ) { 425 | 0, 0, 0, 0, 426 | 42, 0, 0, 45, 427 | 84, 0, 0,255, 428 | 127, 42, 0,255, 429 | 170, 255, 0,255, 430 | 212, 255, 55,255, 431 | 255, 255,255,255}; 432 | 433 | // Gradient palette "BlacK_Magenta_Red_gp", originally from 434 | // http://soliton.vm.bytemark.co.uk/pub/cpt-city/nd/basic/tn/BlacK_Magenta_Red.png.index.html 435 | // converted for FastLED with gammas (2.6, 2.2, 2.5) 436 | // Size: 20 bytes of program space. 437 | 438 | DEFINE_GRADIENT_PALETTE( BlacK_Magenta_Red_gp ) { 439 | 0, 0, 0, 0, 440 | 63, 42, 0, 45, 441 | 127, 255, 0,255, 442 | 191, 255, 0, 45, 443 | 255, 255, 0, 0}; 444 | 445 | // Gradient palette "BlacK_Red_Magenta_Yellow_gp", originally from 446 | // http://soliton.vm.bytemark.co.uk/pub/cpt-city/nd/basic/tn/BlacK_Red_Magenta_Yellow.png.index.html 447 | // converted for FastLED with gammas (2.6, 2.2, 2.5) 448 | // Size: 28 bytes of program space. 449 | 450 | DEFINE_GRADIENT_PALETTE( BlacK_Red_Magenta_Yellow_gp ) { 451 | 0, 0, 0, 0, 452 | 42, 42, 0, 0, 453 | 84, 255, 0, 0, 454 | 127, 255, 0, 45, 455 | 170, 255, 0,255, 456 | 212, 255, 55, 45, 457 | 255, 255,255, 0}; 458 | 459 | // Gradient palette "Blue_Cyan_Yellow_gp", originally from 460 | // http://soliton.vm.bytemark.co.uk/pub/cpt-city/nd/basic/tn/Blue_Cyan_Yellow.png.index.html 461 | // converted for FastLED with gammas (2.6, 2.2, 2.5) 462 | // Size: 20 bytes of program space. 463 | 464 | DEFINE_GRADIENT_PALETTE( Blue_Cyan_Yellow_gp ) { 465 | 0, 0, 0,255, 466 | 63, 0, 55,255, 467 | 127, 0,255,255, 468 | 191, 42,255, 45, 469 | 255, 255,255, 0}; 470 | 471 | 472 | // Single array of defined cpt-city color palettes. 473 | // This will let us programmatically choose one based on 474 | // a number, rather than having to activate each explicitly 475 | // by name every time. 476 | // Since it is const, this array could also be moved 477 | // into PROGMEM to save SRAM, but for simplicity of illustration 478 | // we'll keep it in a regular SRAM array. 479 | // 480 | // This list of color palettes acts as a "playlist"; you can 481 | // add or delete, or re-arrange as you wish. 482 | const TProgmemRGBGradientPalettePtr GradientPalettes[] = { 483 | Sunset_Real_gp, 484 | es_rivendell_15_gp, 485 | es_ocean_breeze_036_gp, 486 | rgi_15_gp, 487 | retro2_16_gp, 488 | Analogous_1_gp, 489 | es_pinksplash_08_gp, 490 | Coral_reef_gp, 491 | es_ocean_breeze_068_gp, 492 | es_pinksplash_07_gp, 493 | es_vintage_01_gp, 494 | departure_gp, 495 | es_landscape_64_gp, 496 | es_landscape_33_gp, 497 | rainbowsherbet_gp, 498 | gr65_hult_gp, 499 | gr64_hult_gp, 500 | GMT_drywet_gp, 501 | ib_jul01_gp, 502 | es_vintage_57_gp, 503 | ib15_gp, 504 | Fuschia_7_gp, 505 | es_emerald_dragon_08_gp, 506 | lava_gp, 507 | fire_gp, 508 | Colorfull_gp, 509 | Magenta_Evening_gp, 510 | Pink_Purple_gp, 511 | es_autumn_19_gp, 512 | BlacK_Blue_Magenta_White_gp, 513 | BlacK_Magenta_Red_gp, 514 | BlacK_Red_Magenta_Yellow_gp, 515 | Blue_Cyan_Yellow_gp }; 516 | 517 | 518 | // Count of how many cpt-city gradients are defined: 519 | const uint8_t GradientPaletteCount = 520 | sizeof( GradientPalettes) / sizeof( TProgmemRGBGradientPalettePtr ); 521 | 522 | 523 | #endif 524 | -------------------------------------------------------------------------------- /notasound/jugglep.h: -------------------------------------------------------------------------------- 1 | #ifndef JUGGLEP_H 2 | #define JUGGLEP_H 3 | 4 | void jugglep() { // Use the juggle routine, but adjust the timebase based on sampleAvg for some randomness. 5 | 6 | // Local definitions 7 | 8 | // Persistent local variables 9 | static int thistime = 20; // Time shifted value keeps changing thus interrupting the juggle pattern. 10 | 11 | // Temporary local variables 12 | 13 | 14 | fadeToBlackBy(leds, NUM_LEDS, 32); // Fade the strand. 15 | 16 | leds[beatsin16(thistime,0,NUM_LEDS-1, 0, 0)] += ColorFromPalette( currentPalette, millis()/4, sampleAgc, currentBlending); 17 | leds[beatsin16(thistime-3,0,NUM_LEDS-1, 0, 0)] += ColorFromPalette( currentPalette, millis()/4, sampleAgc, currentBlending); 18 | 19 | EVERY_N_MILLISECONDS(250) { 20 | thistime = sampleAvg/2; // Change the beat frequency every 250 ms. By Andrew Tuline. 21 | } 22 | 23 | } // jugglep() 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /notasound/matrix.h: -------------------------------------------------------------------------------- 1 | #ifndef MATRIX_H 2 | #define MATRIX_H 3 | 4 | void matrix() { // A 'Matrix' like display using sampleavg for brightness. 5 | 6 | // Local definitions 7 | 8 | // Persistent local variables 9 | 10 | // Temporary local variables 11 | 12 | 13 | if (thisdir == 1) { 14 | leds[0] = ColorFromPalette(currentPalette, millis(), sampleAgc*2, currentBlending); 15 | } else { 16 | leds[NUM_LEDS-1] = ColorFromPalette( currentPalette, millis(), sampleAgc*2, currentBlending); 17 | } 18 | 19 | if (thisdir == 1) { 20 | for (int i = NUM_LEDS-1; i >0 ; i-- ) leds[i] = leds[i-1]; 21 | } else { 22 | for (int i = 0; i < NUM_LEDS-1 ; i++ ) leds[i] = leds[i+1]; 23 | } 24 | 25 | } // matrix() 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /notasound/myvumeter.h: -------------------------------------------------------------------------------- 1 | #ifndef MYVUMETER_H 2 | #define MYVUMETER_H 3 | 4 | void myvumeter() { // A vu meter. Grabbed the falling LED from Reko Meriö. 5 | 6 | // Local definitions 7 | #define GRAVITY 2 8 | 9 | // Persistent local variables 10 | static uint8_t topLED; 11 | static int gravityCounter = 0; 12 | 13 | // Temporary local variables 14 | uint8_t tempsamp = constrain(sampleAvg*2,0,NUM_LEDS-1); // Keep the sample from overflowing. 15 | 16 | 17 | fadeToBlackBy(leds, NUM_LEDS, 160); 18 | 19 | for (int i=0; i= topLED) 25 | topLED = tempsamp; 26 | else if (gravityCounter % GRAVITY == 0) 27 | topLED--; 28 | 29 | if (topLED > 0) { 30 | leds[topLED] = ColorFromPalette(currentPalette, millis(), 255, LINEARBLEND); // LED falls when the volume goes down. 31 | } 32 | 33 | gravityCounter = (gravityCounter + 1) % GRAVITY; 34 | 35 | } // myvumeter() 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /notasound/noisewide.h: -------------------------------------------------------------------------------- 1 | #ifndef NOISEWIDE_H 2 | #define NOISEWIDE_H 3 | 4 | void noisewide() { 5 | 6 | // Local definitions 7 | #define GRAVITY 5 8 | 9 | // Persistent local variables 10 | static uint8_t topLED; 11 | static int gravityCounter = 0; 12 | 13 | // Temporary local variables 14 | uint8_t tempsamp = constrain(sampleAvg,0,NUM_LEDS/2-1); // Keep the sample from overflowing. 15 | 16 | 17 | fadeToBlackBy(leds, NUM_LEDS, 160); 18 | 19 | for (int i=0; i= topLED) 26 | topLED = tempsamp; 27 | else if (gravityCounter % GRAVITY == 0) 28 | topLED--; 29 | 30 | if (topLED > 0) { 31 | leds[NUM_LEDS/2-topLED] = ColorFromPalette(currentPalette, millis(), 255, LINEARBLEND); // LED falls when the volume goes down. 32 | leds[topLED+NUM_LEDS/2] = ColorFromPalette(currentPalette, millis(), 255, LINEARBLEND); // LED falls when the volume goes down. 33 | } 34 | 35 | gravityCounter = (gravityCounter + 1) % GRAVITY; 36 | 37 | } // noisewide() 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /notasound/notasound.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * notasound - IR controlled 'synchronized' led lighting effects using FastLED across multiple Arduino AVR based controllers with sound reactive display sequences. 3 | * 4 | * By: Andrew Tuline 5 | * Date: May, 2019 (latest update) 6 | * URL: www.tuline.com 7 | * Email: atuline@gmail.com 8 | * Gist: https://gist.github.com/atuline 9 | * GitHub: https://github.com/atuline 10 | * Youtube: https://www.youtube.com/user/atuline/videos 11 | * 12 | * FastLED Support Forums: https://www.reddit.com/r/FastLED/ 13 | * 14 | * 15 | * This works best with Arduino Nano, a TSOP38238 IR receiver, a 3.3V ADMP401 microphone and APA102 LED's. 16 | * 17 | * CAUTION ************************************************************************************************************************************************ 18 | * 19 | * Before attempting to compile this program, make sure you are already comfortable programming in Arduino C and with FastLED. In addition, you 20 | * should already be able to download, install and USE 3rd party libraries. If you are a beginner, this is NOT the code you're looking for. 21 | * 22 | * Effects in this program are programmed for up to 255 LED's. You will need to re-write it for longer strips. 23 | * 24 | * These have been tested thoroughly on an Arduino Nano, but not other platforms and on the Nano, IR control works great with APA102's, but is unreliable 25 | * with WS2812's. 26 | * 27 | * Note that WS2812's can cause havoc with IR control. 28 | * 29 | * 1) You cannot control them at all on a UNO/Nano while running FastLED. 30 | * 2) On ESP8266's, you have a choice of random LED flashing and good control or smooth a display but with intermittent IR control. 31 | * 3) 32 | * 33 | * 34 | * INTRODUCTION ******************************************************************************************************************************************* 35 | * 36 | * Here's a pile of sound reactive display routines for Arduino microcontrollers (tested on a Nano) and addressable LED strips using the FastLED display library. 37 | * Each Arduino is IR controlled using Nico Hood's IR control library. The sound routines are customized for the 3.3V ADMP401 MEMS microphone. 38 | * 39 | * 40 | * 41 | * 42 | * VERSIONS *********************************************************************************************************************************************** 43 | * 44 | * TODO 45 | * 46 | * More testing of each routine for a quality of display. Let's see if we can make the best of the best. 47 | * 48 | * 1.11 49 | * 50 | * Adding agcAvg functionality and tune up the existing routines. 51 | * Also, try and line up notasound overall functionality with notamesh. 52 | * 53 | * 54 | * 1.10 55 | * 56 | * I forgot to update some of the IR functionality for EEPROM with strand length and mesh delay. That's now fixed. 57 | * Also added more Serial.println statements for button presses. 58 | * Retrofit some updates that I'd made for notamesh. 59 | * 60 | * 61 | * 1.09 62 | * Updated IRLRemote to 2.0.2, which changes my code. Although it does work with WS2812, it doesn't do so very reliably. 63 | * Added Serial.print(F("Text") in order to save on RAM. 64 | * 65 | * 66 | * 1.08 67 | * 68 | * Convert squelch control to save/read from EEPROM. 69 | * Add maxVol changes to increase/decrease peak detection sensitivity and save/read from EEPROM. 70 | * Stop the animation while we're setting strand length or delay. 71 | * Permanently removed strand favourites. A single startup mode should suffice. 72 | * Convert glitter control to save/read from EEPROM. 73 | * Convert brightness control to save/read from EEPROM. 74 | * Convert direction control to save/read from EEPROM. 75 | * Convert delay control to save/read from EEPROM. Not useful, as each routine has its own unique delay. 76 | * 77 | * 78 | * 1.07 Sampling fix, general fixes and a display change. 79 | * 80 | * Change sampling algorithm to direct method. Can sample at various rates, but more complex to use. 81 | * Changed some of the averaging and squelching math. 82 | * Fix the samplepeak detection for the various routines. Each display routine must now reset samplepeak. Wow, what a realization that was. 83 | * Had a problem with it crashing consistently 80 seconds in with 40 LED's. Lowered the max_bright and problem went away. Strange. 84 | * Turned mode 0 from solid red to an ambient noise routine. 85 | * Fixed a couple of displays that addressed leds[NUM_LEDS] 86 | * Adjusted the default squelch value. 87 | * 88 | * 89 | * 1.06 Big update/change by merging notamesh framework with the soundmems demo routines to combine sound reactive functionality with IR control. 90 | * 91 | * Use notamesh framework and combine/update soundmems demos. 92 | * Change potin squelch control to IR control with B4 and C1 buttons. 93 | * Adjust/fix some of the routines to even out sensitivity and limits. 94 | * Update the documentation. 95 | * 96 | * 97 | * 1.05 Update 98 | * 99 | * Set/display a favourite. 100 | * 101 | * 102 | * 1.04 Update 103 | * 104 | * Make programming length and delay to be unit selectable. 105 | * Change demo mode to start at ledMode 2. 106 | * Set default to non-demo mode. 107 | * Add plasma, remove circnoise routines. 108 | * NEW FUNCTIONALITY ---> Supports delayed sequences across Arduinos, which you might see in a mesh network. But it's 'notamesh' network. 109 | * NEW FUNCTIONALITY ---> Use paletteknife palettes (for notamesh palette consistency across multiple strands) rather than the previous random generated ones. 110 | * Re-add STRANDID. 111 | * 112 | * 113 | * 1.03 Update 114 | * 115 | * Convert 'thisdir' direction variable from boolean to -1, 1 and update all directional based routines. 116 | * Reduce direction IR button press to a toggle. 117 | * Fix IR button pressed modes that don't animate. 118 | * Move IR codes to commands.h and update the values to the 24 button pad I have. 119 | * Remove keyboard and button functionality. I don't use it. 120 | * Remove STRANDID and strandactive security features, as well as select individual Arduino. I may bring this back. 121 | * Save strandlength after every change to B2/B3 instead of a separate 'save' command. 122 | * Add EEPROM initialization check and save initial values. 123 | * Add notamesh functionality which configures a delay. It displays 1 white LED per 100ms delay. 124 | * 125 | * 126 | * 1.02 Update and prior 127 | * 128 | * Old stuff, to be sure. 129 | * 130 | * 131 | * HARDWARE SETUP (for Arduino Nano) ********************************************************************************************************************** 132 | * 133 | * This has been developed using an Arduino Nano. 134 | * The LED data line is connected to pin 12. 135 | * The LED clock line is connected to pin 11. 136 | * For IR functionality, connect the data output of a TSOP34838 38kHz IR receiver to pin D2 (other TSOP pins are 5V and Gnd). 137 | * This NOW supports If you use WS2812 LED's (but not very well). 138 | * This is currently configured to support up to 64 LED's. You can increase this by changing MAX_LEDS, up to 255 (not tested) with adequate memory. 139 | * Connect the AREF pin to 3.3V on the Arduino if using a 3.3V microphone (such as the ADMP401). 140 | * Connect the analog output of the ADMP401 to A5 on the Arduino. 141 | * 142 | * 143 | * 144 | * EEPROM Functionality *********************************************************************************************************************************** 145 | * 146 | * Save the startup display mode in EEPROM. 147 | * Save the ID of the strand so that length and meshdelay can be programmed individually. 148 | * Save the strand length in EEPROM, however the MAXIMUM strand length is pre-defined. We just use a lesser value for the array. 149 | * Save the mesh delay in EEPROM by 100ms at a time. 150 | * Save the squelch value in EEPROM, adjustable +/- 1. 151 | * Save the direction in EEPROM, adjustable +/-1. 152 | * Save the brightness in EEPROM, adjustable * or / 2. 153 | * Save the peak detection sensitivity in EEPROM, adjustable +/- 1. 154 | * 155 | * 156 | * Libraries Required (to download) *********************************************************************************************************************** 157 | * 158 | * FastLED library from https://github.com/FastLED/FastLED 159 | * Nico Hood's IRL library from https://github.com/NicoHood/IRLremote 160 | * 161 | * I don't know if there's any conflict between Ken Shiriff's IR Library and Nico's. I'll leave that up to you to sort out. Then there's ESP8266 based IR libraries. 162 | * 163 | * 164 | * Compile Time Configuration ****************************************************************************************************************************** 165 | * 166 | * Configure and compile notasound for your type of strand, microphone, IR and LED pins used. 167 | * Configure the STRANDID value for your Arduino (corresponding to a keypress value). Each Arduino should have a unique STRANDID, and you should write that down. 168 | * Set the demorun startup variable to 1 for demo mode or 0 for regular use. It's configured to 0 (non-demo mode) by default. 169 | * You may need to adjust soundmems.h for your microphone. It's currently configured for an ADMP401. 170 | * You may need to review the analogreference() in setup() for your microphone as well. It's currently configured for the 3.3V ADMP401. 171 | * 172 | * 173 | * First Time Initialization ****************************************************************************************************************************** 174 | * 175 | * The first time notasound runs on an Arduino, the setup program will initialize the EEPROM so that: 176 | * 177 | * An Arduino initialization flag will be set. 178 | * The starting mode will be 0 (a non-sound reactive display). 179 | * The starting NUM_LEDS length will be 20 LED's. 180 | * The starting squelch value is 20. 181 | * The starting maxVol for peak detection is 20. 182 | * 183 | * If you want to re-initialize the EEPROM values, then change the value of INITVAL at compile time. You can also reboot twice within 5 seconds. 184 | * 185 | * 186 | * Notasound Initial Configuration ************************************************************************************************************************ 187 | * 188 | * 1) Set your strand length. 189 | * 190 | * You'll need to 'activate' your strand for EEPROM programming. To do so: 191 | * 192 | * - Press B1 to put the Arduino into 'Select strand' mode. 193 | * - Press the button equivalent to your STRANDID, i.e. C1 to 'activate' your Arduino for EEPROM programming. 194 | * - Press B2 to decrease the strand length. 195 | * - Press B3 to increase the strand length. 196 | * 197 | * LED's will light up as 'white' to indicate the strand length. The strand length will be saved to EEPROM after each keypress. 198 | * Once done, press B1 again or press A3 to reset the Arduino. 199 | * 200 | * 201 | * Notasound Operation ********************************************************************************************************************************** 202 | * 203 | * The notasound initial configuration is important so that there's a different delay between each LED strip. 204 | * Press A3 once all notasound Arduinos are running in order to synchronize them with the same millis() value. 205 | * From there, you should be able to select demo mode or individual sequences below. 206 | * The routines should run and you should get a cool synchronized display across the strips. 207 | * 208 | * Note: Although the delay functionality doesn't work with notasound, each strand running the same sequence will look a bit different, 209 | * depending on the location of the microphone. 210 | * 211 | * 212 | * 213 | * IR Keys and Operation ******************************************************************************************************************************** 214 | * 215 | * This configuration uses a 24 button IR remote like the ones provided with 5V LED strands from China. If you use a different one, you'll need to map 216 | * the codes to the modes in the irtest(); routine in the commands.h file. 217 | * 218 | * The chart below summarizes the commands. Button location uses characters as the row, and numbers are the columns, so C2 is the 3rd row, 2nd column. 219 | * 220 | * 221 | * Command IR Button location & description 222 | * -------- -------------------------------- 223 | * Increase brightness A1 Increase brightness 224 | * Decrease brightness A2 Decrease brightness 225 | * Reset and set mode 0 A3 Reboots the Arduino in order to sync millis() if using notasound. Factory reset if < 2 seconds. 226 | * Enable demo mode A4 Demo mode cycles through the routines based on the millis() counter. Not a toggle. 227 | * 228 | * Select Arduino B1 This allows the EEPROM to be updated. Then press A1 through F4 as configured with STRANDID at compile time. (not A3 or B1 though). 229 | * Decrease strand length B2 The # of LED's programmed are white, only if strand is active (via B1 & STRANDID). This is saved in EEPROM. Press B1 again or A3 to reboot when done. 230 | * Increase strand length B3 The # of LED's programmed are white, only if strand is active (via B1 & STRANDID). This is saved in EEPROM. Press B1 again or A3 to reboot when done. 231 | * B4 232 | 233 | * C1 234 | * Slower animation C2 Increase value of EVERY_N_MILLISECONDS() for the current (fixed) display mode. 235 | * Faster animation C3 Decrease value of EVERY_N_MILLISECONDS() for the current (fixed) display mode. 236 | * Toggle direction C4 Toggle direction of some sequences. This is saved in EEPROM however very few demos use it. 237 | * 238 | * Decrease maxVol D1 Which increases peak detection sensitivity. This is saved in EEPROM. 239 | * Increase maxVol D2 Which decreases peak detection sensitivity. This is saved in EEPROM. 240 | * Decrease noise squelch D3 Allows more ambient noise is displayed. This is saved in EEPROM. 241 | * Increase noise squelch D4 Increases noise squelch, so that ambient noise = 0. This is saved in EEPROM. 242 | * 243 | * Stop palette rotation E1 Stop palette rotation at current palette. Save palette to EEPROM. 244 | * Select previous palette E2 Stop palette rotation and select previous palette immediately. Save palette to EEPROM. 245 | * Select next palette E3 Stop palette rotation and select next palette immediately. Save Palette to EEPROM. 246 | * Enable palette rotation E4 Enable palette transitioning every 5 seconds. 247 | * 248 | * F1 249 | * Previous display mode F2 Also disables demo mode. 250 | * Next display mode F3 Also disables demo mode. 251 | * Save Current mode to EEPROM F4 This will be the startup mode, and disables demo mode temporarily. This is saved in EEPROM. 252 | * 253 | * 254 | */ 255 | 256 | 257 | /*------------------------------------------------------------------------------------------ 258 | --------------------------------------- Start of variables --------------------------------- 259 | ------------------------------------------------------------------------------------------*/ 260 | 261 | 262 | #define _ESP8266 // Uncomment this if using ESP8266. It's required for EEPROM changes between the platforms. 263 | //#define _NANO // Uncomment this if using UNO/Nano or similar AVR. 264 | 265 | #define qsubd(x, b) ((x>b)?x:0) // A digital unsigned subtraction macro. if result <0, then => 0. Otherwise, take on fixed value. 266 | #define qsuba(x, b) ((x>b)?x-b:0) // Unsigned subtraction macro. if result <0, then => 0. 267 | 268 | #define NOTASOUND_VERSION 110 // Just a continuation of notamesh, previously seirlight and previous to that was irlight, then aalight and then atlight. Turtles. . . 269 | 270 | //#define FASTLED_ALLOW_INTERRUPTS 0 // Used for ESP8266. 271 | #include // FastLED library. 272 | 273 | #include "IRLremote.h" // https://github.com/NicoHood/IRLremote 274 | #include "EEPROM.h" // This is included with base install 275 | 276 | #include "commands.h" // The IR commands transmitted from the keypad. 277 | 278 | #if IRL_VERSION < 202 279 | #error "Requires IRLRemote 2.0.2 or later. Check github for latest code." 280 | #endif 281 | 282 | #if FASTLED_VERSION < 3001000 283 | #error "Requires FastLED 3.1 or later. Check github for latest code." 284 | #endif 285 | 286 | #define pinIR D2 // Choose a valid PinInterrupt pin of your Arduino board for IR operations. In this case, D2. 287 | #define IRL_BLOCKING true 288 | uint16_t IRAddress; 289 | uint8_t IRCommand; 290 | 291 | CNec IRLremote; 292 | 293 | 294 | // Fixed definitions cannot change on the fly. 295 | #define LED_DT D5 // Serial data pin for all strands 296 | #define LED_CK D4 // Serial clock pin for WS2801 or APA102 297 | #define COLOR_ORDER GRB // It's GRB for WS2812 298 | #define LED_TYPE WS2812 // Alternatively WS2801, or WS2812 299 | #define MAX_LEDS 64 // Maximum number of LED's defined (at compile time). 300 | 301 | #define MIC_PIN A0 // Analog port for microphone 302 | uint8_t squelch = 7; // Anything below this is background noise, so we'll make it '0'. 303 | int sample; // Current sample. 304 | float sampleAvg = 0; // Smoothed Average. 305 | float micLev = 0; // Used to convert returned value to have '0' as minimum. 306 | uint8_t maxVol = 15; // Reasonable value for constant volume for 'peak detector', as it won't always trigger. 307 | bool samplePeak = 0; // Boolean flag for peak. Responding routine must reset this flag. 308 | 309 | int sampleAgc, multAgc; 310 | uint8_t targetAgc = 60; // This is our setPoint at 20% of max for the adjusted output. 311 | 312 | 313 | // Initialize changeable global variables. 314 | uint8_t NUM_LEDS; // Number of LED's we're actually using, and we can change this only the fly for the strand length. 315 | 316 | uint8_t max_bright = 128; // Overall brightness definition. It can be changed on the fly. 317 | 318 | struct CRGB leds[MAX_LEDS]; // Initialize our LED array. We'll be using less in operation. 319 | 320 | CRGBPalette16 currentPalette; // Use palettes instead of direct CHSV or CRGB assignments. 321 | CRGBPalette16 targetPalette; // Also support smooth palette transitioning. 322 | 323 | TBlendType currentBlending = LINEARBLEND; // NOBLEND or LINEARBLEND for palettes 324 | 325 | extern const TProgmemRGBGradientPalettePtr GradientPalettes[]; // These are for the fixed palettes in gradient_palettes.h 326 | extern const uint8_t GradientPaletteCount; // Total number of fixed palettes to display. 327 | uint8_t currentPaletteNumber = 0; // Current palette number from the 'playlist' of color palettes 328 | uint8_t currentPatternIndex = 0; // Index number of which pattern is current 329 | 330 | 331 | // EEPROM location definitions. 332 | #define ISINIT 0 // EEPROM location used to verify that this Arduino has been initialized. 333 | #define STARTMODE 1 // EEPROM location for the starting mode. 334 | #define STRANDLEN 2 // EEPROM location for the actual Length of the strand, which is < MAX_LEDS 335 | #define STRANDEL 3 // EEPROM location for the mesh delay value. 336 | 337 | #define STARTPAL 6 // EEPROM location of current palette. If !0, then rotation = 0. 338 | #define GLIT 7 // EEPROM location for glitter. 339 | #define BRIT 8 // EEPROM location is brightness. 340 | #define SPED 9 // EEPROM location of speed. 341 | #define DIRN 10 // EEPROM location of direction. 342 | #define LHUE 11 // EEPROM location of lamp hue. 343 | #define LSAT 12 // EEPROM location of lamp saturation. 344 | #define DEMO 13 // EEPROM location of demo mode toggle. 345 | 346 | #define SQU 20 // EEPROM location of squelch. 347 | #define MXV 21 // EEPROM location of maxVol. 348 | 349 | 350 | #define INITVAL 0x55 // If this is the value in ISINIT, then the Arduino has been initialized. Change to completely reset your Arduino. 351 | 352 | 353 | #define INITBRIT 255 // Initial max_bright. 354 | #define INITDEL 0 // Starting mesh delay value of the strand in milliseconds. 355 | #define INITDIRN 1 // Initial thisdir value. 356 | #define INITGLIT 0 // Glitter is off by default. 357 | #define INITLEN 30 // Start length is 20 LED's. 358 | #define INITMODE 0 // Startmode is 0, which is black. 359 | #define INITPAL 0 // Starting palette number. 360 | #define INITSPED 0 // Initial thisdelay value. 361 | #define INITLHUE 0 // Initial lamphue value (not used). 362 | #define INITLSAT 1 // Initial lampsat value (not used). 363 | #define INITDEMO 1 // Initial demo mode value. 364 | 365 | #define INITMAX 9 // Starting maxVol value. 366 | #define INITSQU 7 // Starting squelch value. 367 | 368 | 369 | const uint32_t STRANDID = IR_C1; // This is the ID button of the strand and should be unique for each strand in a series (if you want them to be different). 370 | bool strandActive = 0; // Used for configuration changes only. 0=inactive, 1=active. Must be activated by button press of B1, followed by C1 (or the appropriate STRANDID button). 371 | bool strandFlag = 0; // Flag to let us know if we're changing the active strand. 372 | 373 | uint16_t meshdelay; // Timer for the notasound. Works with INITDEL. 374 | 375 | uint8_t ledMode = 0; // Starting mode is typically 0. Change INITMODE if you want a different starting mode. 376 | uint8_t demorun = 0; // 0 = regular mode, 1 = demo mode, 2 = shuffle mode. 377 | uint8_t maxMode = 16; // Maximum mode number. 378 | uint16_t demotime = 10; // Set the length of the demo timer. 379 | 380 | 381 | // Generic/shared routine variables ---------------------------------------------------------------------- 382 | uint16_t loops = 0; // Our loops per second counter for showfps(). 383 | uint8_t lamphue = 0; // Hue value of lamp mode. 384 | uint8_t lampsat = 1; // Saturation value of lamp mode. 385 | 386 | 387 | // IR changeable variables 388 | uint8_t palchg = 3; // 0=no change, 1=similar, 2=random 389 | uint8_t thisdelay; // Standard delay is initialized by EEPROM. 390 | uint8_t glitter; // Glitter flag is initialized by EEPROM. 391 | int8_t thisdir; // Standard direction is either -1 or 1. Used as a multiplier rather than boolean and is initialized by EEPROM. 392 | 393 | 394 | 395 | // Display functions ----------------------------------------------------------------------- 396 | 397 | // Support functions 398 | #include "getsample.h" // New sound reactive routines. 399 | #include "support.h" // Support routines, such as showfps, glitter and routines to move up/down strand. 400 | #include "gradient_palettes.h" // Using fixed gradient palettes rather than random ones. 401 | 402 | 403 | // Main sound reactive routines 404 | 405 | #include "besin.h" // sampleAgc - Center to edges with black 406 | #include "fillnoise.h" // sampleAvg & sampleAgc - Center to edges with base color and twinkle 407 | #include "fire.h" // sampleAvg - Start to end noise based fire 408 | #include "firewide.h" // sampleAvg - Center to edges 409 | #include "jugglep.h" // sampleAgc - Long line of sinewaves 410 | #include "matrix.h" // sample - Start to end with twinkles 411 | #include "myvumeter.h" // sampleAvg - My own vu meter 412 | #include "noisewide.h" // sampleAvg - Center to edges 413 | #include "onesine.h" // sampleAvg - Long line of shortlines 414 | #include "pixelblend.h" // sampleAgc - Long line of blended colours 415 | #include "pixels.h" // sampleAgc - Long line of individual colours 416 | #include "plasma.h" // sampleAgc - Long line of short lines 417 | #include "plasma2.h" // 418 | #include "rainbowpeak.h" // samplepeak - Long line of short lines with twinkles 419 | #include "ripple.h" // samplepeak - Juggle with twinkles 420 | #include "sinephase.h" // sampleAgc - Changing phases of sine waves 421 | 422 | 423 | /*------------------------------------------------------------------------------------------ 424 | --------------------------------------- Start of code -------------------------------------- 425 | ------------------------------------------------------------------------------------------*/ 426 | 427 | void setup() { 428 | 429 | Serial.begin(115200); // Setup serial baud rate 430 | delay(1000); // Slow startup so we can re-upload in the case of errors. 431 | 432 | Serial.println(F(" ")); Serial.println(F("---SETTING UP notasound---")); 433 | 434 | // analogReference(EXTERNAL); // Comment out this line for 3.3V Arduino's, ie. Flora, etc or if powering microphone with 5V. 435 | 436 | if (!IRLremote.begin(pinIR)) 437 | Serial.println(F("You did not choose a valid pin.")); 438 | 439 | // LEDS.addLeds(leds, MAX_LEDS); // APA102 or WS2801 4 pin definition. 440 | LEDS.addLeds(leds, MAX_LEDS); // WS2812 3 pin definition. 441 | 442 | FastLED.setMaxPowerInVoltsAndMilliamps(5, 500); // 5V, 500mA maximum power draw. 443 | 444 | #if defined(_ESP8266) 445 | EEPROM.begin(32); // Not used by the UNO/Nano, but critical for ESP8266. 446 | #endif 447 | 448 | 449 | if (EEPROM.read(ISINIT) != INITVAL) { // Check to see if Arduino has been initialized, and if not, do so. A cold reset as it were. 450 | EEPROM.write(ISINIT, INITVAL); // Initialize the starting value (so we know it's initialized) to INITVAL. 451 | 452 | EEPROM.write(BRIT, INITBRIT); // Initialize the brightness value. 453 | EEPROM.write(STRANDEL, INITDEL); // Initialize the notamesh delay to 0. 454 | EEPROM.write(DIRN, INITDIRN); // Initial thisdir value. 455 | EEPROM.write(GLIT, INITGLIT); // Initialize glitter value. 456 | EEPROM.write(STRANDLEN, INITLEN); // Initialize the starting length to 20 LED's. 457 | EEPROM.write(STARTMODE, INITMODE); // Initialize the starting mode to 0. 458 | EEPROM.write(STARTPAL, INITPAL); // Initialize the palette to 0. 459 | EEPROM.write(SPED, INITSPED); // Initial thisdelay value. 460 | EEPROM.write(LHUE, INITLHUE); // Initial lamphue value. 461 | EEPROM.write(LSAT, INITLSAT); // Initial lampsat value. 462 | EEPROM.write(DEMO, INITDEMO); 463 | 464 | EEPROM.write(SQU, INITSQU); // Initialize the squelch value. 465 | EEPROM.write(MXV, INITMAX); // Initialize maxVol value. 466 | 467 | Serial.println(F("Cold reset.")); 468 | } 469 | 470 | 471 | ledMode = EEPROM.read(STARTMODE); // Location 0 is the starting mode. 472 | NUM_LEDS = EEPROM.read(STRANDLEN); // Need to ensure NUM_LEDS < MAX_LEDS elsewhere. 473 | meshdelay = EEPROM.read(STRANDEL); // This is our notamesh delay for cool delays across strands. 474 | glitter = EEPROM.read(GLIT); // notamesh glitter. 475 | max_bright = EEPROM.read(BRIT); // max_bright value. 476 | thisdelay = EEPROM.read(SPED); // thisdelay value. 477 | thisdir = EEPROM.read(DIRN); // thisdir value. 478 | lamphue = EEPROM.read(LHUE); // lamphue value. 479 | lampsat = EEPROM.read(LSAT); // lampsat value. 480 | demorun = EEPROM.read(DEMO); 481 | 482 | squelch = EEPROM.read(SQU); // notasound squelch is stored in EEPROM. 483 | maxVol = EEPROM.read(MXV); // notasound maxVol for peak detection in EEPROM. 484 | 485 | 486 | if (EEPROM.read(STARTPAL) != 0) {currentPaletteNumber = EEPROM.read(STARTPAL); palchg = 0;} 487 | 488 | Serial.println(F("---EEPROM COMPLETE---")); 489 | 490 | Serial.print(F("Initial mesh delay: ")); Serial.print(meshdelay*100); Serial.println(F("ms delay")); 491 | Serial.print(F("Initial strand length: ")); Serial.print(NUM_LEDS); Serial.println(F(" LEDs")); 492 | Serial.print(F("Strand ID: ")); Serial.println(STRANDID); 493 | Serial.print(F("Glitter: ")); Serial.println(glitter); 494 | Serial.print(F("Brightness: ")); Serial.println(max_bright); 495 | Serial.print(F("Delay: ")); Serial.println(thisdelay); 496 | Serial.print(F("Direction: ")); Serial.println(thisdir); 497 | Serial.print(F("Palette: ")); Serial.println(currentPaletteNumber); 498 | Serial.print(F("Demo: ")); Serial.println(demorun); 499 | 500 | Serial.print(F("Squelch: ")); Serial.println(squelch); 501 | Serial.print(F("Maxvol: ")); Serial.println(maxVol); 502 | 503 | LEDS.setBrightness(max_bright); // Set the generic maximum brightness value. 504 | 505 | currentPalette = CRGBPalette16(CRGB::Black); 506 | targetPalette = (GradientPalettes[0]); 507 | 508 | strobe_mode(ledMode, 1); // Initialize the first sequence. 509 | 510 | Serial.println(F("---SETUP COMPLETE---")); Serial.println(F(" ")); 511 | 512 | } // setup() 513 | 514 | 515 | 516 | //------------------MAIN LOOP--------------------------------------------------------------- 517 | void loop() { 518 | 519 | getSample(); // Sample sound, measure averages and detect peak. 520 | agcAvg(); 521 | 522 | getirl(); // Read a command from the IR LED and process command as required. 523 | 524 | demo_check(); // If we're in demo mode, check the timer to see if we need to increase the strobe_mode value. 525 | 526 | EVERY_N_MILLISECONDS(50) { // Smooth palette transitioning runs continuously. 527 | uint8_t maxChanges = 24; 528 | nblendPaletteTowardPalette(currentPalette, targetPalette, maxChanges); 529 | } 530 | 531 | EVERY_N_SECONDS(5) { // If selected, change the target palette to a random one every 5 seconds. 532 | if (palchg==3) { 533 | currentPaletteNumber = addmod8(currentPaletteNumber, 1, GradientPaletteCount); 534 | } 535 | targetPalette = GradientPalettes[currentPaletteNumber]; // We're just ensuring that the targetPalette WILL be assigned. 536 | } 537 | 538 | EVERY_N_MILLIS_I(thistimer, thisdelay) { // Sets the original delay time. 539 | thistimer.setPeriod(thisdelay); // This is how you update the delay value on the fly. 540 | strobe_mode(ledMode, 0); // Strobe to display the current sequence, but don't initialize the variables, so mc=0; 541 | } 542 | 543 | if(glitter) addGlitter(sampleAvg/2); // If the glitter flag is set, let's add some. 544 | 545 | if (!IRLremote.receiving()) { 546 | FastLED.show(); // Power managed display of LED's. 547 | } 548 | 549 | } // loop() 550 | 551 | 552 | 553 | //-------------------OTHER ROUTINES---------------------------------------------------------- 554 | void strobe_mode(uint8_t newMode, bool mc){ // mc stands for 'Mode Change', where mc = 0 is to display the routine, while mc = 1 is to initialize and then display the routine. 555 | 556 | if(mc) { 557 | fill_solid(leds,NUM_LEDS,CRGB(0,0,0)); // Clean up the array for the first time through. Don't show display though, so you may have a smooth transition. 558 | Serial.print(F("Mode: ")); 559 | Serial.println(newMode); 560 | } 561 | 562 | if (!strandActive) { // Stops the display sequence if we're updating the EEPROM in ACTIVE mode. 563 | switch (newMode) { // If first time through a new mode, then initialize the variables for a given display, otherwise, just call the routine. 564 | case 0: if(mc) {thisdelay=40;} matrix(); break; // sampleAgc - Start to end 565 | case 1: if(mc) {thisdelay=20;} ripple(); break; // samplepeak - Juggle with twinkles 566 | case 2: if(mc) {thisdelay=40;} fillnoise(); break; // sampleAvg - Center to edges with base color and twinkle 567 | case 3: if(mc) {thisdelay=0;} pixelblend(); break; // sampleAgc - Pixel blending 568 | case 4: if(mc) {thisdelay=10;} sinephase(); break; // sampleAvg - Changing phases of sine waves 569 | case 5: if(mc) {thisdelay=30;} onesine(); break; // sampleAvg - Long line of shortlines 570 | case 6: if(mc) {thisdelay=10;} rainbowpeak(); break; // samplepeak - Long line of short lines with twinkles 571 | case 7: if(mc) {thisdelay=10;} noisewide(); break; // sampleAvg - Center to edges 572 | case 8: if(mc) {thisdelay=30;} myvumeter(); break; // sampleAvg - My own vu meter 573 | case 9: if(mc) {thisdelay=10;} jugglep(); break; // sampleAvg - Long line of sinewaves 574 | case 10: if(mc) {thisdelay=10;} firewide(); break; // sampleAvg - Center to edges 575 | case 11: if(mc) {thisdelay=0;} pixels(); break; // sampleAgc - Long line of colours 576 | case 12: if(mc) {thisdelay=20;} plasma(); break; // sampleAvg - Long line of short lines 577 | case 13: if(mc) {thisdelay=30;} besin(); break; // sampleAvg - Center to edges with black 578 | case 14: if(mc) {thisdelay=0;} fire(); break; // sampleAvg - Start to end noise based fire 579 | case 15: if(mc) {thisdelay=0;} plasma2(); break; // sampleAvg - Start to end noise based fire 580 | 581 | default: break; 582 | } // switch newMode 583 | } // !strandActive 584 | 585 | } // strobe_mode() 586 | 587 | 588 | 589 | void demo_check(){ // Are we in demo mode or not, and if so, change the routine every 'demotime' seconds. 590 | 591 | if(demorun) { // Is the demo flag set? If so, let's cycle through them. 592 | uint16_t secondHand = (millis() / 1000) % (maxMode*demotime+1); // Adjust for total time of the loop, based on total number of available modes. 593 | 594 | static uint16_t lastSecond = 99; // Static variable, means it's only defined once. This is our 'debounce' variable. 595 | if (lastSecond != secondHand) { // Debounce to make sure we're not repeating an assignment. 596 | lastSecond = secondHand; 597 | if(secondHand%demotime==0) { // Every 10 seconds. 598 | if(demorun == 2) ledMode = random8(0,maxMode); else { // Shuffle mode, which is not used. 599 | ledMode = secondHand/demotime; 600 | } 601 | meshwait(); 602 | strobe_mode(ledMode,1); // Does NOT reset to 0. 603 | } // if secondHand 604 | } // if lastSecond 605 | } // if demorun 606 | 607 | } // demo_check() 608 | 609 | 610 | //----------------- IR Receiver and Button Command Processing --------------------------------------------- 611 | 612 | void getirl() { // This is the IR function that gets the value and selects/performs a command. 613 | 614 | if (IRLremote.available()) { 615 | 616 | auto irdata = IRLremote.read(); // Get the new data from the remote. 617 | IRAddress = irdata.address; // Do this if we want to swap out values. 618 | IRCommand = irdata.command; // Do this if we want to swap out values. 619 | 620 | // if(strandFlag == 1) set_strand(); // Set the strand length 621 | 622 | // Serial.print(F("Address: ")); // Print the protocol data. Note that there's also 65535, which we don't use. 623 | // Serial.println(irdata.address); 624 | // Serial.print(F("Command: ")); 625 | // Serial.println(irdata.command); 626 | // Serial.println(); 627 | 628 | if (IRAddress == IR_ADD) { 629 | switch(IRCommand) { 630 | 631 | case IR_A1: max_bright=min(max_bright*2+1,255); EEPROM.write(BRIT, max_bright); Serial.print(F("Bright: ")); Serial.println(max_bright); LEDS.setBrightness(max_bright); break; //a1 - Increase max bright 632 | case IR_A2: max_bright=max(max_bright/2,0); EEPROM.write(BRIT, max_bright); Serial.print(F("Bright: ")); Serial.println(max_bright); LEDS.setBrightness(max_bright); break; //a2 - Decrease max bright 633 | case IR_A3: fill_solid(leds,NUM_LEDS,CRGB(0,0,0)); FastLED.show(); Serial.println(F("Rebooting . . ")); FastLED.delay(100); bootme(); break; //a3 - Change to mode 0, display and reboot 634 | case IR_A4: demorun = 1; EEPROM.write(DEMO, demorun); Serial.println(F("Demo mode")); break; //a4 - Enable demo mode 635 | 636 | case IR_B1: Serial.println(F("Activate request")); set_strand(); break; //b1 - Set Strand Active or Inactive for EEPROM programming. 637 | case IR_B2: if (strandActive==1) set_strandlen(); break; //b2 - Decrease # of LED's and write to EEPROM 638 | case IR_B3: if (strandActive==1) set_strandlen(); break; //b3 - Increase # of LED's and write to EEPROM 639 | // case IR_B4: if (strandActive==1) set_meshdel(); break; //b4 - Shorter mesh delay by 100ms 640 | 641 | // case IR_C1: if (strandActive==1) set_meshdel(); break; //c1 - Longer mesh delay by 100ms 642 | case IR_C2: thisdelay++; EEPROM.write(SPED, thisdelay); Serial.print(F("Delay: ")); Serial.println(thisdelay); break; //c2 - Slow down the sequence as much as you want. 643 | case IR_C3: thisdelay--; if(thisdelay >30000) thisdelay = 0; EEPROM.write(SPED, thisdelay); Serial.print(F("Delay: ")); Serial.println(thisdelay); break; //c3 - Speed up the sequence, but don't go too far. 644 | case IR_C4: thisdir = thisdir*-1; EEPROM.write(DIRN, thisdir); Serial.print(F("thisdir = ")); Serial.println(thisdir); break; //c4 - Change the direction of the LEDs. 645 | 646 | case IR_D1: maxVol--; if(maxVol <0) maxVol = 0; EEPROM.write(MXV, maxVol);Serial.print(F("Maxvol: ")); Serial.println(maxVol); break; //d1 - Reduce maxVol for more sensitive peak detection 647 | case IR_D2: maxVol++; EEPROM.write(MXV, maxVol);Serial.print(F("Maxvol: ")); Serial.println(maxVol); break; //d2 - Increase maxVol for less sensitive peak detection 648 | case IR_D3: squelch--; if(squelch <0) squelch = 0; EEPROM.write(SQU, squelch);Serial.print(F("Squelch: ")); Serial.println(squelch); break; //d3 - Reduce squelch value 649 | case IR_D4: squelch++; EEPROM.write(SQU, squelch); Serial.print(F("Squelch: ")); Serial.println(squelch); break; //d4 - Increase squelch value. 650 | 651 | // case IR_D1: glitter = !glitter; EEPROM.write(GLIT, glitter); Serial.print(F("Glitter is: ")); Serial.println(glitter); break; //d1 - Toggle glitter. 652 | // case IR_D2: demorun = 0; ledMode=(ledMode-1); if (ledMode==255) ledMode=maxMode; meshwait(); strobe_mode(ledMode,1); break; //d2 - Stop demo and display previous mode. 653 | // case IR_D3: demorun = 0; ledMode=(ledMode+1)%(maxMode+1); meshwait(); strobe_mode(ledMode,1); break; //d3 - stop demo and display next mode. 654 | // case IR_D4: EEPROM.write(STARTMODE,ledMode); Serial.print(F("Writing startup mode: ")); Serial.println(ledMode); break; //d4 - Save current mode as startup mode. 655 | 656 | case IR_E1: palchg = 0; Serial.print(F("Stop and select current Palette: ")); EEPROM.write(STARTPAL, currentPaletteNumber); Serial.println(currentPaletteNumber); break; //f1 - Stop and select current Palette 657 | case IR_E2: palchg = 1; Serial.print(F("Stop and select previous Palette: ")); currentPaletteNumber -= 1; if(currentPaletteNumber == 255) currentPaletteNumber = GradientPaletteCount; EEPROM.write(STARTPAL, currentPaletteNumber); Serial.println(currentPaletteNumber); currentPalette = (GradientPalettes[currentPaletteNumber]); break; //f2 - Stop and select previous Palette 658 | case IR_E3: palchg = 2; Serial.print(F("Stop and select next Palette: ")); currentPaletteNumber = addmod8( currentPaletteNumber, 1, GradientPaletteCount); EEPROM.write(STARTPAL, currentPaletteNumber); Serial.println(currentPaletteNumber); currentPalette = (GradientPalettes[currentPaletteNumber]); break; //f3 - Stop and select next Palette 659 | case IR_E4: palchg = 3; Serial.print(F("Continuous palette change: ")); Serial.println(currentPaletteNumber); EEPROM.write(STARTPAL, 0); break; //f4 - Continuous palette change 660 | 661 | // case IR_F1: palchg = 4; Serial.println(F("Hue/Palette based palette change.")); EEPROM.write(STARTPAL, 4); break; //d1 - Hue/saturation palette. 662 | case IR_F1: break; //f1 - Hue/saturation palette. 663 | case IR_F2: demorun = 0; EEPROM.write(DEMO, demorun); ledMode=(ledMode-1); if (ledMode==255) ledMode=maxMode; meshwait(); strobe_mode(ledMode,1); break; //f2 - strobe_mode(ledMode--); 664 | case IR_F3: demorun = 0; EEPROM.write(DEMO, demorun); ledMode=(ledMode+1)%(maxMode+1); meshwait(); strobe_mode(ledMode,1); break; //f3 - strobe_mode(ledMode++); 665 | case IR_F4: EEPROM.write(STARTMODE,ledMode); Serial.print(F("Writing startup mode: ")); Serial.println(ledMode); break; //f4 - Save startup mode 666 | 667 | default: break; // We could do something by default. 668 | 669 | } // switch IRCommand 670 | } // if IR_ADD 671 | } // if IRLRemote 672 | 673 | } // getirl() 674 | 675 | 676 | 677 | void bootme() { // This is used to reset all the Arduinos so that their millis() counters are all in sync. 678 | 679 | if (millis() < 5000) { 680 | Serial.println(F("Factory Reset.")); // If we reset within 5 seconds of startup, then it means factory reset. 681 | EEPROM.write(ISINIT, 0); 682 | delay(200); 683 | } 684 | 685 | #if defined(_ESP8266) 686 | EEPROM.commit(); // We need to actually write to the EEPROM on the ESP8266. Am not sprinkling this throughout the existing code, so here it sits. 687 | ESP.restart(); 688 | #endif 689 | 690 | #if defined(_NANO) 691 | asm volatile("jmp 0"); 692 | #endif 693 | 694 | } // bootme() 695 | 696 | 697 | 698 | void meshwait() { // After we press a mode key, we need to wait a bit for the sequence to start. 699 | 700 | // Serial.print(F("Mesh delay: ")); Serial.print(meshdelay*100); Serial.println(F("ms delay.")); 701 | FastLED.delay(meshdelay*100); // Here's our notasound wait upon keypress. I'm so sorry there's a delay statement here. At least it's only used upon mode change keypress. Makes life a LOT simpler. 702 | 703 | } // meshwait() 704 | 705 | 706 | 707 | void set_strand() { // Setting the active strand. This logic is not great, so we have to reboot when done. 708 | 709 | if (IRAddress == IR_ADD && IRCommand == IR_B1) { 710 | strandFlag = !strandFlag; 711 | if (strandFlag == false) {IRCommand = 255; strandActive = 0; Serial.println(F("INACTIVE"));} 712 | } 713 | 714 | if (strandFlag == true && IRAddress == IR_ADD && IRCommand == STRANDID) { 715 | strandActive = 1; Serial.println(F("ACTIVE")); 716 | } 717 | 718 | } // set_strand() 719 | 720 | 721 | 722 | void set_strandlen() { // Setting our strand length with button presses. 723 | 724 | Serial.println(F("Setting strand length.")); 725 | 726 | if(strandActive == 1) { // Only do this if the strand is active. 727 | demorun = 0; // First we disable the demo mode. 728 | fill_solid(leds,MAX_LEDS, CRGB::Black); // Let's make it black manually. 729 | 730 | if (IRCommand == IR_B2) { 731 | NUM_LEDS--; if (NUM_LEDS >255) NUM_LEDS=0; // Don't be stupid with our strand length selection. 732 | } else { 733 | NUM_LEDS++; if (NUM_LEDS >= MAX_LEDS) NUM_LEDS=MAX_LEDS-1; // Again, don't be stupid with our strand length selection. 734 | } 735 | fill_solid(leds,NUM_LEDS,CRGB(64, 64, 64)); // Turn on the number of LEDs that we have selected as our length. 736 | EEPROM.write(STRANDLEN,NUM_LEDS); // Write that value to EEPROM. 737 | Serial.print(F("Writing IR: ")); Serial.print(NUM_LEDS); Serial.println(F(" LEDs")); 738 | } // if strandActive 739 | 740 | } // set_strandlen() 741 | 742 | 743 | 744 | void set_meshdel() { // Setting our notasound delay for whatever strands are powered up. 745 | 746 | if(strandActive == 1) { // Only do this if the strand is active. 747 | demorun = 0; // First we disable the demo mode. 748 | ledMode = 0; // And set to mode 0 (black). 749 | fill_solid(leds,MAX_LEDS, CRGB::Black); // Let's make it black manually. 750 | 751 | if (IRCommand == IR_E2) { // Which button did we press (either E2 or E3). 752 | meshdelay = meshdelay - 1; 753 | if (meshdelay >10000) meshdelay = 0; // Again, don't be stupid with our buttons. 754 | } else { 755 | meshdelay = meshdelay + 1; // Increase the delay as much as you want. . . 756 | } // if IRCommand 757 | 758 | fill_solid(leds,meshdelay,CRGB(64, 64, 64)); // Turn on the number of LED's that we have selected (100ms is 1 LED) 759 | EEPROM.write(STRANDEL,meshdelay); // Write out the delay to EEPROM. 760 | Serial.print(F("Writing IR: ")); Serial.print(meshdelay*100); Serial.println(F("ms delay.")); 761 | } // if strandActive 762 | 763 | } // set_meshdel() 764 | -------------------------------------------------------------------------------- /notasound/onesine.h: -------------------------------------------------------------------------------- 1 | #ifndef ONESINE_H 2 | #define ONESINE_H 3 | 4 | void onesine() { 5 | 6 | // Local definitions 7 | 8 | // Persistent local variable. 9 | static int thisphase = 0; // Phase change value gets calculated. 10 | 11 | // Temporary local variables 12 | uint8_t allfreq = 32; // You can change the frequency, thus distance between bars. Wouldn't recommend changing on the fly. 13 | uint8_t thiscutoff; // You can change the cutoff value to display this wave. Lower value = longer wave. 14 | 15 | 16 | thiscutoff = 255 - sampleAgc; 17 | 18 | thisphase += sampleAvg/2 + beatsin16(20,-10,10); // Move the sine waves along as a function of sound plus a bit of sine wave. 19 | 20 | for (int k=0; kb)?x-b:0) // Unsigned subtraction macro. if result <0, then => 0. 27 | 28 | leds[k] += ColorFromPalette( currentPalette, colorIndex, thisbright, currentBlending); // Let's now add the foreground colour. 29 | } 30 | 31 | fadeToBlackBy(leds, NUM_LEDS, 64); 32 | 33 | } // plasma() 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /notasound/plasma2.h: -------------------------------------------------------------------------------- 1 | #ifndef PLASMA2_H 2 | #define PLASMA2_H 3 | 4 | 5 | 6 | void plasma2() { // This is the heart of this program. Sure is short. . . and fast. 7 | 8 | // fadeToBlackBy(leds, NUM_LEDS, 8); 9 | 10 | int thisPhase = beatsin8(6,-64,64); // Setting phase change for a couple of waves. 11 | int thatPhase = beatsin8(7,-64,64); 12 | 13 | int thisFreq = beatsin8(8,10,20); 14 | int thatFreq = beatsin8(15,15,30); 15 | 16 | 17 | for (int k=0; k 1000 19 | 20 | if(currentMillis - lastMillis >1000) { // If 1 second has passed, then. . 21 | Serial.println(loops); // Print the value of loops (which is loops per second). 22 | lastMillis = currentMillis; // Reset everything and start counting all over again. By Andrew Tuline. 23 | loops = 0; 24 | } 25 | 26 | } // showfps() 27 | 28 | 29 | 30 | // Supporting visual functions ---------------------------------------------------------------------------------------------- 31 | 32 | 33 | 34 | void addGlitter(fract8 chanceOfGlitter) { // Let's add some glitter 35 | 36 | if( random8() < chanceOfGlitter) { 37 | leds[random16(NUM_LEDS)] += CRGB::White; 38 | } 39 | 40 | } // addGlitter() 41 | 42 | 43 | 44 | void lineit() { // Send the pixels one or the other direction down the line. 45 | 46 | if (thisdir == 0) { 47 | for (int i = NUM_LEDS-1; i >0 ; i-- ) leds[i] = leds[i-1]; 48 | } else { 49 | for (int i = 0; i < NUM_LEDS-1 ; i++ ) leds[i] = leds[i+1]; 50 | } 51 | 52 | } // lineit() 53 | 54 | 55 | 56 | void waveit() { // Shifting pixels from the center to the left and right. 57 | 58 | for (int i = NUM_LEDS - 1; i > NUM_LEDS/2; i--) { // Move to the right. 59 | leds[i] = leds[i - 1]; 60 | } 61 | 62 | for (int i = 0; i < NUM_LEDS/2; i++) { // Move to the left. 63 | leds[i] = leds[i + 1]; 64 | } 65 | 66 | } // waveit() 67 | 68 | 69 | #endif 70 | -------------------------------------------------------------------------------- /sound_bracelet/sound_bracelet.ino: -------------------------------------------------------------------------------- 1 | /* sound_bracelet 2 | * 3 | * By: Jon Burroughs 4 | * 5 | * Converted to FastLED by: Andrew Tuline 6 | * 7 | * Date: October, 2014 8 | * 9 | * soundbracelet was based Neopixel code by Jon Burroughs: 10 | * 11 | * https://www.youtube.com/watch?v=JjX8X5D8RW0&feature=youtu.be 12 | * https://plus.google.com/105445034001275025240/posts/jK2fxRx79kj 13 | * http://www.slickstreamer.info/2014/07/led-bracelet-vu-meter-3dprinting.html 14 | * 15 | * That was based on the Adafruit LED Ampli-tie project at: 16 | * 17 | * https://learn.adafruit.com/led-ampli-tie/overview 18 | * 19 | * This version was written for a Sparkfun INMP401 MEMS microphone/pre-amp. In this case, it's plugged into A5 of the Arduino. 20 | * 21 | * Plug Vcc of the microphone into 3.3V of Arduino. Connect 3.3V of Arduino to the AREF pin, and gnd to gnd. 22 | * 23 | * 24 | */ 25 | 26 | 27 | #include "FastLED.h" // FastLED library. 28 | 29 | #if FASTLED_VERSION < 3001000 30 | #error "Requires FastLED 3.1 or later; check github for latest code." 31 | #endif 32 | 33 | // Fixed definitions cannot change on the fly. 34 | #define LED_DT 12 // Data pin to connect to the strip. 35 | #define LED_CK 11 // Clock pin for WS2801 or APA102. 36 | #define COLOR_ORDER GRB // It's GRB for WS2812 and BGR for APA102. 37 | #define LED_TYPE WS2812 // Using APA102, WS2812, WS2801. Don't forget to modify LEDS.addLeds to suit. 38 | #define NUM_LEDS 30 // Number of LED's. 39 | 40 | // Initialize changeable global variables. 41 | uint8_t max_bright = 255; // Overall brightness definition. It can be changed on the fly. 42 | 43 | struct CRGB leds[NUM_LEDS]; // Initialize our LED array. 44 | 45 | #define MIC_PIN 5 // Analog port for microphone 46 | 47 | #define DC_OFFSET 0 // DC offset in mic signal - if unusure, leave 0 48 | // I calculated this value by serialprintln lots of mic values 49 | #define NOISE 30 // Noise/hum/interference in mic signal and increased value until it went quiet 50 | #define SAMPLES 60 // Length of buffer for dynamic level adjustment 51 | #define TOP (NUM_LEDS + 2) // Allow dot to go slightly off scale 52 | #define PEAK_FALL 10 // Rate of peak falling dot 53 | 54 | byte 55 | peak = 0, // Used for falling dot 56 | dotCount = 0, // Frame counter for delaying dot-falling speed 57 | volCount = 0; // Frame counter for storing past volume data 58 | int 59 | vol[SAMPLES], // Collection of prior volume samples 60 | lvl = 10, // Current "dampened" audio level 61 | minLvlAvg = 0, // For dynamic adjustment of graph low & high 62 | maxLvlAvg = 512; 63 | 64 | 65 | 66 | void setup() { 67 | 68 | // This is only needed on 5V Arduinos (Uno, Leonardo, etc.). Connect 3.3V to mic AND TO AREF ON ARDUINO and enable this 69 | // line. Audio samples are 'cleaner' at 3.3V. COMMENT OUT THE FOLLOWING LINE FOR 3.3V ARDUINOS (FLORA, ETC.): 70 | analogReference(EXTERNAL); 71 | 72 | Serial.begin(115200); // Initialize serial port for debugging. 73 | delay(1000); // Soft startup to ease the flow of electrons. 74 | 75 | LEDS.addLeds(leds, NUM_LEDS); // Use this for WS2812B 76 | // LEDS.addLeds(leds, NUM_LEDS); // Use this for WS2801 or APA102 77 | 78 | FastLED.setBrightness(max_bright); 79 | FastLED.setMaxPowerInVoltsAndMilliamps(5, 500); // FastLED 2.1 Power management set at 5V, 500mA 80 | 81 | } // setup() 82 | 83 | 84 | 85 | void loop() { 86 | 87 | soundbracelet(); 88 | FastLED.show(); // Power managed FastLED display 89 | 90 | } // loop() 91 | 92 | 93 | 94 | void soundbracelet() { 95 | 96 | uint8_t i; 97 | uint16_t minLvl, maxLvl; 98 | int n, height; 99 | 100 | n = analogRead(MIC_PIN); // Raw reading from mic 101 | n = abs(n - 512 - DC_OFFSET); // Center on zero 102 | 103 | Serial.println(n); 104 | 105 | n = (n <= NOISE) ? 0 : (n - NOISE); // Remove noise/hum 106 | lvl = ((lvl * 7) + n) >> 3; // "Dampened" reading (else looks twitchy) 107 | 108 | // Calculate bar height based on dynamic min/max levels (fixed point): 109 | height = TOP * (lvl - minLvlAvg) / (long)(maxLvlAvg - minLvlAvg); 110 | 111 | if (height < 0L) height = 0; // Clip output 112 | else if (height > TOP) height = TOP; 113 | if (height > peak) peak = height; // Keep 'peak' dot at top 114 | 115 | 116 | // Color pixels based on rainbow gradient 117 | for (i=0; i= height) leds[i].setRGB( 0, 0,0); 119 | else leds[i] = CHSV(map(i,0,NUM_LEDS-1,30,150), 255, 255); 120 | } 121 | 122 | // Draw peak dot 123 | if (peak > 0 && peak <= NUM_LEDS-1) leds[peak] = CHSV(map(peak,0,NUM_LEDS-1,30,150), 255, 255); 124 | 125 | // Every few frames, make the peak pixel drop by 1: 126 | 127 | if (++dotCount >= PEAK_FALL) { // fall rate 128 | if(peak > 0) peak--; 129 | dotCount = 0; 130 | } 131 | 132 | vol[volCount] = n; // Save sample for dynamic leveling 133 | if (++volCount >= SAMPLES) volCount = 0; // Advance/rollover sample counter 134 | 135 | // Get volume range of prior frames 136 | minLvl = maxLvl = vol[0]; 137 | for (i=1; i maxLvl) maxLvl = vol[i]; 140 | } 141 | // minLvl and maxLvl indicate the volume range over prior frames, used 142 | // for vertically scaling the output graph (so it looks interesting 143 | // regardless of volume level). If they're too close together though 144 | // (e.g. at very low volume levels) the graph becomes super coarse 145 | // and 'jumpy'...so keep some minimum distance between them (this 146 | // also lets the graph go to zero when no sound is playing): 147 | if((maxLvl - minLvl) < TOP) maxLvl = minLvl + TOP; 148 | minLvlAvg = (minLvlAvg * 63 + minLvl) >> 6; // Dampen min/max levels 149 | maxLvlAvg = (maxLvlAvg * 63 + maxLvl) >> 6; // (fake rolling average) 150 | 151 | } // fastbracelet() 152 | -------------------------------------------------------------------------------- /sound_noise/sound_noise.ino: -------------------------------------------------------------------------------- 1 | /* sound_noise 2 | * 3 | * By: Andrew Tuline 4 | * 5 | * Date: February, 2017 6 | * 7 | * Updated: January, 2020 8 | * 9 | * Another sound reactive routine that works with Perlin noise. 10 | * 11 | * Uses: sampleAvg 12 | * 13 | * 14 | */ 15 | 16 | #define FASTLED_ALLOW_INTERRUPTS 0 // Used for ESP8266. 17 | #include "FastLED.h" // FastLED library. 18 | 19 | #define MIC_PIN 5 // Analog port for microphone 20 | uint8_t squelch = 7; // Anything below this is background noise, so we'll make it '0'. 21 | int sample; // Current sample. 22 | float sampleAvg = 0; // Smoothed Average. 23 | float micLev = 0; // Used to convert returned value to have '0' as minimum. 24 | uint8_t maxVol = 11; // Reasonable value for constant volume for 'peak detector', as it won't always trigger. 25 | bool samplePeak = 0; // Boolean flag for peak. Responding routine must reset this flag. 26 | 27 | 28 | // Fixed definitions cannot change on the fly. 29 | #define LED_DT 12 // Data pin to connect to the strip. 30 | #define LED_CK 11 31 | #define COLOR_ORDER GRB // It's GRB for WS2812B and BGR for APA102 32 | #define LED_TYPE WS2812 // What kind of strip are you using (WS2801, WS2812B or APA102)? 33 | #define NUM_LEDS 30 // Number of LED's. 34 | 35 | struct CRGB leds[NUM_LEDS]; // Initialize our LED array. 36 | 37 | CRGBPalette16 currentPalette(OceanColors_p); 38 | CRGBPalette16 targetPalette(LavaColors_p); 39 | TBlendType currentBlending; // NOBLEND or LINEARBLEND 40 | 41 | 42 | 43 | int max_bright = 255; 44 | 45 | 46 | 47 | static int16_t xdist; // A random number for our noise generator. 48 | static int16_t ydist; 49 | uint16_t xscale = 30; // Wouldn't recommend changing this on the fly, or the animation will be really blocky. 50 | uint16_t yscale = 30; // Wouldn't recommend changing this on the fly, or the animation will be really blocky. 51 | uint8_t maxChanges = 24; // Value for blending between palettes. 52 | 53 | 54 | 55 | void setup() { 56 | 57 | analogReference(EXTERNAL); // 3.3V reference for analog input. 58 | 59 | Serial.begin(115200); 60 | Serial.println("The start!"); 61 | 62 | LEDS.addLeds(leds, NUM_LEDS); // Use this for WS2812B 63 | // LEDS.addLeds(leds, NUM_LEDS); // Use this for WS2801 or APA102 64 | 65 | FastLED.setBrightness(max_bright); 66 | FastLED.setMaxPowerInVoltsAndMilliamps(5, 500); 67 | 68 | } // setup() 69 | 70 | 71 | 72 | void loop() { 73 | 74 | EVERY_N_MILLISECONDS(10) { 75 | uint8_t maxChanges = 24; 76 | nblendPaletteTowardPalette(currentPalette, targetPalette, maxChanges); // AWESOME palette blending capability. 77 | fillnoise8(); // Update the LED array with noise based on sound input 78 | fadeToBlackBy(leds, NUM_LEDS, 32); // 8 bit, 1 = slow, 255 = fast 79 | } 80 | 81 | EVERY_N_SECONDS(5) { // Change the target palette to a random one every 5 seconds. 82 | targetPalette = CRGBPalette16(CHSV(random8(), 255, random8(128,255)), CHSV(random8(), 255, random8(128,255)), CHSV(random8(), 192, random8(128,255)), CHSV(random8(), 255, random8(128,255))); 83 | } 84 | 85 | getSample(); // Sample the sound. 86 | 87 | FastLED.show(); // Display everything. 88 | 89 | } // loop() 90 | 91 | 92 | 93 | void getSample() { 94 | 95 | int16_t micIn; // Current sample starts with negative values and large values, which is why it's 16 bit signed. 96 | static long peakTime; 97 | 98 | micIn = analogRead(MIC_PIN); // Poor man's analog Read. 99 | micLev = ((micLev * 31) + micIn) / 32; // Smooth it out over the last 32 samples for automatic centering. 100 | micIn -= micLev; // Let's center it to 0 now. 101 | micIn = abs(micIn); // And get the absolute value of each sample. 102 | sample = (micIn <= squelch) ? 0 : (sample + micIn) / 2; // Using a ternary operator, the resultant sample is either 0 or it's a bit smoothed out with the last sample. 103 | sampleAvg = ((sampleAvg * 31) + sample) / 32; // Smooth it out over the last 32 samples. 104 | 105 | if (sample > (sampleAvg+maxVol) && millis() > (peakTime + 50)) { // Poor man's beat detection by seeing if sample > Average + some value. 106 | samplePeak = 1; // Then we got a peak, else we don't. Display routines need to reset the samplepeak value in case they miss the trigger. 107 | peakTime=millis(); 108 | } 109 | 110 | } // getSample() 111 | 112 | 113 | 114 | void fillnoise8() { // Add Perlin noise with modifiers from the soundmems routine. 115 | 116 | int maxLen = sampleAvg; 117 | if (sampleAvg >NUM_LEDS) maxLen = NUM_LEDS; 118 | 119 | for (int i = (NUM_LEDS-maxLen)/2; i <(NUM_LEDS+maxLen+1)/2; i++) { // The louder the sound, the wider the soundbar. 120 | uint8_t index = inoise8(i*sampleAvg+xdist, ydist+i*sampleAvg); // Get a value from the noise function. I'm using both x and y axis. 121 | // uint8_t index = inoise8(xdist+i*xscale, ydist+i*yscale) % 255; // Get a value from the noise function. I'm using both x and y axis. 122 | leds[i] = ColorFromPalette(currentPalette, index, 255, LINEARBLEND); // With that value, look up the 8 bit colour palette value and assign it to the current LED. 123 | } 124 | 125 | xdist=xdist+beatsin8(5,0,10); 126 | ydist=ydist+beatsin8(4,0,10); 127 | 128 | } // fillnoise8() 129 | -------------------------------------------------------------------------------- /sound_pal/sound_pal.ino: -------------------------------------------------------------------------------- 1 | /* sound_pal 2 | * 3 | * By: Andrew Tuline 4 | * 5 | * Date: June 2015 6 | * 7 | * Code to read from the Sparkfun INMP401 microphone on pin A5 and display a palette based output. 8 | * 9 | * Light up led[0] and propagate to the other end. 10 | * 11 | */ 12 | 13 | #include "FastLED.h" // FastLED library. 14 | 15 | #if FASTLED_VERSION < 3001000 16 | #error "Requires FastLED 3.1 or later; check github for latest code." 17 | #endif 18 | 19 | // Use qsuba for smooth pixel colouring and qsubd for non-smooth pixel colouring 20 | #define qsubd(x, b) ((x>b)?b:0) // Digital unsigned subtraction macro. if result <0, then => 0. Otherwise, take on fixed value. 21 | #define qsuba(x, b) ((x>b)?x-b:0) // Analog Unsigned subtraction macro. if result <0, then => 0 22 | 23 | // Fixed definitions cannot change on the fly. 24 | #define LED_DT 12 // Data pin to connect to the strip. 25 | #define LED_CK 11 // Clock pin for WS2801 or APA102. 26 | #define COLOR_ORDER GRB // It's GRB for WS2812 and BGR for APA102. 27 | #define LED_TYPE WS2812 // Using APA102, WS2812, WS2801. Don't forget to modify LEDS.addLeds to suit. 28 | #define NUM_LEDS 30 // Number of LED's. 29 | 30 | 31 | #define MIC_PIN 5 // Analog port for microphone 32 | uint8_t squelch = 7; // Anything below this is background noise, so we'll make it '0'. 33 | int sample; // Current sample. 34 | float sampleAvg = 0; // Smoothed Average. 35 | float micLev = 0; // Used to convert returned value to have '0' as minimum. 36 | uint8_t maxVol = 11; // Reasonable value for constant volume for 'peak detector', as it won't always trigger. 37 | bool samplePeak = 0; // Boolean flag for peak. Responding routine must reset this flag. 38 | 39 | int sampleAgc, multAgc; 40 | uint8_t targetAgc = 60; // This is our setPoint at 20% of max for the adjusted output. 41 | 42 | 43 | uint8_t max_bright = 255; // Overall brightness definition. It can be changed on the fly. 44 | 45 | struct CRGB leds[NUM_LEDS]; // Initialize our LED array. 46 | 47 | CRGBPalette16 currentPalette; 48 | CRGBPalette16 targetPalette; 49 | TBlendType currentBlending = LINEARBLEND; // NOBLEND or LINEARBLEND 50 | 51 | 52 | 53 | void setup() { 54 | 55 | analogReference(EXTERNAL); 56 | 57 | Serial.begin(115200); // Initialize serial port for debugging. 58 | delay(1000); // Soft startup to ease the flow of electrons. 59 | 60 | LEDS.addLeds(leds, NUM_LEDS); 61 | // LEDS.addLeds(leds, NUM_LEDS); 62 | 63 | FastLED.setBrightness(max_bright); 64 | FastLED.setMaxPowerInVoltsAndMilliamps(5, 500); // FastLED Power management set at 5V, 500mA. 65 | 66 | } // setup() 67 | 68 | 69 | 70 | void loop() { 71 | 72 | EVERY_N_SECONDS(5) { // Change the target palette to a random one every 5 seconds. 73 | static uint8_t baseC = random8(32); // You can use this as a baseline colour if you want similar hues in the next line. 74 | for (int i = 0; i < 16; i++) targetPalette[i] = CHSV(random8()+baseC, 255, 255); 75 | } 76 | 77 | EVERY_N_MILLISECONDS(100) { 78 | uint8_t maxChanges = 24; 79 | nblendPaletteTowardPalette(currentPalette, targetPalette, maxChanges); // AWESOME palette blending capability. 80 | } 81 | 82 | EVERY_N_MILLISECONDS(20) { // FastLED based non-blocking delay to update/display the sequence. 83 | getSample(); 84 | agcAvg(); 85 | propPal(); 86 | } 87 | 88 | FastLED.show(); 89 | 90 | } // loop() 91 | 92 | 93 | 94 | void getSample() { 95 | 96 | int16_t micIn; // Current sample starts with negative values and large values, which is why it's 16 bit signed. 97 | static long peakTime; 98 | 99 | micIn = analogRead(MIC_PIN); // Poor man's analog Read. 100 | micLev = ((micLev * 31) + micIn) / 32; // Smooth it out over the last 32 samples for automatic centering. 101 | micIn -= micLev; // Let's center it to 0 now. 102 | micIn = abs(micIn); // And get the absolute value of each sample. 103 | sample = (micIn <= squelch) ? 0 : (sample + micIn) / 2; // Using a ternary operator, the resultant sample is either 0 or it's a bit smoothed out with the last sample. 104 | sampleAvg = ((sampleAvg * 31) + sample) / 32; // Smooth it out over the last 32 samples. 105 | 106 | if (sample > (sampleAvg+maxVol) && millis() > (peakTime + 50)) { // Poor man's beat detection by seeing if sample > Average + some value. 107 | samplePeak = 1; // Then we got a peak, else we don't. Display routines need to reset the samplepeak value in case they miss the trigger. 108 | peakTime=millis(); 109 | } 110 | 111 | } // getSample() 112 | 113 | 114 | void agcAvg() { // A simple averaging multiplier to automatically adjust sound sensitivity. 115 | 116 | multAgc = (sampleAvg < 1) ? targetAgc : targetAgc / sampleAvg; // Make the multiplier so that sampleAvg * multiplier = setpoint 117 | sampleAgc = sample * multAgc; 118 | if (sampleAgc > 255) sampleAgc = 255; 119 | 120 | //------------ Oscilloscope output --------------------------- 121 | // Serial.print(targetAgc); Serial.print(" "); 122 | // Serial.print(multAgc); Serial.print(" "); 123 | // Serial.print(sampleAgc); Serial.print(" "); 124 | 125 | // Serial.print(micLev); Serial.print(" "); 126 | // Serial.print(sample); Serial.println(" "); 127 | // Serial.print(sampleAvg); Serial.print(" "); 128 | // Serial.print(micLev); Serial.print(" "); 129 | // Serial.print(samplePeak); Serial.print(" "); samplePeak = 0; 130 | // Serial.print(100); Serial.print(" "); 131 | // Serial.print(0); Serial.print(" "); 132 | // Serial.println(" "); 133 | 134 | } // agcAvg() 135 | 136 | 137 | 138 | void propPal() { 139 | 140 | leds[0] = ColorFromPalette(currentPalette, sampleAgc, sampleAgc, currentBlending); 141 | 142 | for (int i = NUM_LEDS-1; i>0; i--) { // Propagate up the strand. 143 | leds[i] = leds[i-1]; 144 | } 145 | 146 | } // proPal() 147 | -------------------------------------------------------------------------------- /sound_ripple/sound_ripple.ino: -------------------------------------------------------------------------------- 1 | /* soundmems_ripple 2 | * 3 | * By: Andrew Tuline 4 | * 5 | * Date: August, 2015 6 | * 7 | * Updated: January, 2020 8 | * 9 | * Create a ripple from a calculated peak from a sampled microphone 10 | * 11 | * Note: If you are using a microphone powered by the 3.3V signal, such as the Sparkfun MEMS microphone, then connect 3.3V to the AREF pin. 12 | * 13 | */ 14 | 15 | 16 | //#define FASTLED_ALLOW_INTERRUPTS 0 // Used for ESP8266. 17 | #include // FastLED library. 18 | 19 | // Fixed definitions cannot change on the fly. 20 | #define LED_DT 12 // Data pin to connect to the strip. 21 | #define LED_CK 11 // Clock pin for WS2801 or APA102. 22 | #define COLOR_ORDER GRB // It's GRB for WS2812 and BGR for APA102. 23 | #define LED_TYPE WS2812 // Using APA102, WS2812, WS2801. Don't forget to modify LEDS.addLeds to suit. 24 | #define NUM_LEDS 30 // Number of LED's. 25 | 26 | #define MIC_PIN 5 // Analog port for microphone 27 | uint8_t squelch = 7; // Anything below this is background noise, so we'll make it '0'. 28 | int sample; // Current sample. 29 | float sampleAvg = 0; // Smoothed Average. 30 | float micLev = 0; // Used to convert returned value to have '0' as minimum. 31 | uint8_t maxVol = 11; // Reasonable value for constant volume for 'peak detector', as it won't always trigger. 32 | bool samplePeak = 0; // Boolean flag for peak. Responding routine must reset this flag. 33 | 34 | struct CRGB leds[NUM_LEDS]; // Initialize our LED array. 35 | 36 | int max_bright = 255; 37 | 38 | 39 | // Ripple variables 40 | uint8_t colour; // Ripple colour is randomized. 41 | int center = 0; // Center of the current ripple. 42 | int step = -1; // -1 is the initializing step. 43 | uint8_t myfade = 255; // Starting brightness. 44 | #define maxsteps 16 // Case statement wouldn't allow a variable. 45 | 46 | 47 | 48 | void setup() { 49 | 50 | analogReference(EXTERNAL); // 3.3V reference for analog input. 51 | 52 | Serial.begin(115200); 53 | 54 | LEDS.addLeds(leds, NUM_LEDS); // Use this for WS2812B 55 | // LEDS.addLeds(leds, NUM_LEDS); // Use this for WS2801 or APA102 56 | 57 | FastLED.setBrightness(max_bright); 58 | FastLED.setMaxPowerInVoltsAndMilliamps(5, 500); 59 | 60 | } // setup() 61 | 62 | 63 | 64 | void loop() { 65 | 66 | getSample(); 67 | 68 | EVERY_N_MILLISECONDS(20) { 69 | ripple(); 70 | } 71 | 72 | FastLED.show(); 73 | 74 | } // loop() 75 | 76 | 77 | 78 | void getSample() { 79 | 80 | int16_t micIn; // Current sample starts with negative values and large values, which is why it's 16 bit signed. 81 | static long peakTime; 82 | 83 | micIn = analogRead(MIC_PIN); // Poor man's analog Read. 84 | micLev = ((micLev * 31) + micIn) / 32; // Smooth it out over the last 32 samples for automatic centering. 85 | micIn -= micLev; // Let's center it to 0 now. 86 | micIn = abs(micIn); // And get the absolute value of each sample. 87 | sample = (micIn <= squelch) ? 0 : (sample + micIn) / 2; // Using a ternary operator, the resultant sample is either 0 or it's a bit smoothed out with the last sample. 88 | sampleAvg = ((sampleAvg * 31) + sample) / 32; // Smooth it out over the last 32 samples. 89 | 90 | if (sample > (sampleAvg+maxVol) && millis() > (peakTime + 50)) { // Poor man's beat detection by seeing if sample > Average + some value. 91 | samplePeak = 1; // Then we got a peak, else we don't. Display routines need to reset the samplepeak value in case they miss the trigger. 92 | peakTime=millis(); 93 | } 94 | 95 | } // getSample() 96 | 97 | 98 | 99 | void ripple() { 100 | 101 | if (samplePeak == 1) {step = -1; samplePeak = 0; } // If we have a peak, let's reset our ripple. 102 | 103 | fadeToBlackBy(leds, NUM_LEDS, 64); // 8 bit, 1 = slow, 255 = fast 104 | 105 | switch (step) { 106 | 107 | case -1: // Initialize ripple variables. 108 | center = random(NUM_LEDS); 109 | colour = random8(); // More peaks/s = higher the hue colour. 110 | step = 0; 111 | break; 112 | 113 | case 0: 114 | leds[center] = CHSV(colour, 255, 255); // Display the first pixel of the ripple. 115 | step ++; 116 | break; 117 | 118 | case maxsteps: // At the end of the ripples. 119 | // step = -1; 120 | break; 121 | 122 | default: // Middle of the ripples. 123 | leds[(center + step + NUM_LEDS) % NUM_LEDS] += CHSV(colour, 255, myfade/step*2); // Simple wrap. 124 | leds[(center - step + NUM_LEDS) % NUM_LEDS] += CHSV(colour, 255, myfade/step*2); 125 | step ++; // Next step. 126 | break; 127 | } // switch step 128 | 129 | } // ripple() 130 | -------------------------------------------------------------------------------- /sound_sample/sound_sample.ino: -------------------------------------------------------------------------------- 1 | /* sound_sample 2 | * 3 | * By: Andrew Tuline 4 | * 5 | * Date: January, 2020 6 | * 7 | * Basic code to read and print values from a microphone. Includes an auto-leveller to handle any DC offsets. 8 | * 9 | * If your microphone uses 3.3 with a 5V Arduino, then please read up on analogReference(EXTERNAL) in the setup(). 10 | * 11 | * You will, however, need to play around with the squelch value in order to remove background noise. 12 | * 13 | * Note: Be very careful when defining the data type. I had defined micLev and sampleAvg as 'int' as the data was 14 | * within that range, however small errors crept up as a result of the iterative multiplications to the point that 15 | * it was causing significant issues at low sound levels. I eventually had to use floating point. 16 | * 17 | * Moral of the story: KNOW YOUR DATA! 18 | * 19 | */ 20 | 21 | //#define FASTLED_ALLOW_INTERRUPTS 0 // Used for ESP8266. 22 | #include // FastLED library. 23 | 24 | #define MIC_PIN 5 // Analog port for microphone 25 | uint8_t squelch = 7; // Anything below this is background noise, so we'll make it '0'. 26 | int sample; // Current sample. 27 | float sampleAvg = 0; // Smoothed Average. 28 | float micLev = 0; // Used to convert returned value to have '0' as minimum. 29 | uint8_t maxVol = 11; // Reasonable value for constant volume for 'peak detector', as it won't always trigger. 30 | bool samplePeak = 0; // Boolean flag for peak. 31 | 32 | 33 | void setup() { 34 | 35 | analogReference(EXTERNAL); 36 | Serial.begin(115200); // Initialize serial port for debugging. 37 | 38 | } // setup() 39 | 40 | 41 | 42 | void loop() { 43 | 44 | getSample(); 45 | 46 | } // loop() 47 | 48 | 49 | 50 | void getSample() { 51 | 52 | int16_t micIn; // Current sample starts with negative values and large values, which is why it's 16 bit signed. 53 | static long peakTime; 54 | 55 | micIn = analogRead(MIC_PIN); // Poor man's analog Read. 56 | micLev = ((micLev * 31) + micIn) / 32; // Smooth it out over the last 32 samples for automatic centering. 57 | 58 | micIn -= micLev; // Let's center it to 0 now. 59 | micIn = abs(micIn); // And get the absolute value of each sample. 60 | sample = (micIn <= squelch) ? 0 : (sample + micIn)/2; // Using a ternary operator, the resultant sample is either 0 or it's a bit smoothed out with the last sample. 61 | sampleAvg = ((sampleAvg * 31) + sample) / 32; // Smooth it out over the last 32 samples. 62 | 63 | if (sample > (sampleAvg+maxVol) && millis() > (peakTime + 50)) { // Poor man's beat detection by seeing if sample > Average + some value. 64 | samplePeak = 1; 65 | peakTime=millis(); 66 | } // Then we got a peak, else we don't. Display routines need to reset the samplepeak value in case they miss the trigger. 67 | 68 | //------------ Oscilloscope output --------------------------- 69 | // Serial.print(micLev); Serial.print(" "); 70 | Serial.print(sample); Serial.print(" "); 71 | // Serial.print(micLev); Serial.print(" "); 72 | // Serial.print(sampleAvg); Serial.print(" "); 73 | // Serial.print(samplePeak); Serial.print(" "); samplePeak = 0; 74 | // Serial.print(0); Serial.print(" "); 75 | // Serial.print(255); Serial.print(" "); 76 | Serial.println(" "); 77 | 78 | } // getSample() 79 | -------------------------------------------------------------------------------- /sound_wave/sound_wave.ino: -------------------------------------------------------------------------------- 1 | 2 | /* sound_wave 3 | * 4 | * By: Andrew Tuline 5 | * 6 | * Date: February, 2017 7 | * 8 | * Basic code to read from the Sparkfun INMP401 microphone, and create waves based on sampled input. This does NOT include sensitivity adjustment. 9 | * 10 | * My hardware setup: 11 | * 12 | * Arduino Nano & Addressable LED strips 13 | * - Powered by USB power bank 14 | * - APA102 or WS2812 data connected to pin 12. 15 | * - APA102 clock connected to pin 11. 16 | * - 5V on APA102 or WS2812 connected to 5V on Nano (good for short strips). 17 | * - Gnd to Gnd on Nano. 18 | * 19 | * 20 | * Sparkfun MEMS microphone 21 | * - Vcc on microphone is connected to 3.3V on Nano. 22 | * - AREF on Nano connected to 3.3V on Nano. 23 | * - Mic out connected to A5. 24 | * - Gnd to Gnd on Nano. 25 | * 26 | * Note: If you are using a microphone powered by the 3.3V signal, such as the Sparkfun MEMS microphone, then connect 3.3V to the AREF pin. 27 | * 28 | */ 29 | 30 | //#define FASTLED_ALLOW_INTERRUPTS 0 // Used for ESP8266. 31 | #include // FastLED library. 32 | 33 | 34 | #define MIC_PIN 5 // Analog port for microphone 35 | uint8_t squelch = 7; // Anything below this is background noise, so we'll make it '0'. 36 | int sample; // Current sample. 37 | float sampleAvg = 0; // Smoothed Average. 38 | float micLev = 0; // Used to convert returned value to have '0' as minimum. 39 | uint8_t maxVol = 11; // Reasonable value for constant volume for 'peak detector', as it won't always trigger. 40 | bool samplePeak = 0; // Boolean flag for peak. Responding routine must reset this flag. 41 | 42 | int sampleAgc, multAgc; 43 | uint8_t targetAgc = 60; // This is our setPoint at 20% of max for the adjusted output. 44 | 45 | 46 | // Fixed definitions cannot change on the fly. 47 | #define LED_DT 12 // Data pin to connect to the strip. 48 | #define LED_CK 11 // Clock pin for WS2801 or APA102. 49 | #define COLOR_ORDER GRB // It's GRB for WS2812 and BGR for APA102. 50 | #define LED_TYPE WS2812 // Using APA102, WS2812, WS2801. Don't forget to modify LEDS.addLeds to suit. 51 | #define NUM_LEDS 30 // Number of LED's. 52 | 53 | 54 | struct CRGB leds[NUM_LEDS]; // Initialize our LED array. 55 | 56 | int max_bright = 255; 57 | 58 | CRGBPalette16 currentPalette = OceanColors_p; 59 | CRGBPalette16 targetPalette = OceanColors_p; 60 | TBlendType currentBlending = LINEARBLEND; // NOBLEND or LINEARBLEND 61 | 62 | 63 | 64 | void setup() { 65 | analogReference(EXTERNAL); // 3.3V reference for analog input. 66 | 67 | Serial.begin(115200); // Initialize serial port for debugging. 68 | delay(1000); // Soft startup to ease the flow of electrons. 69 | 70 | LEDS.addLeds(leds, NUM_LEDS); // Use this for WS2812B 71 | // LEDS.addLeds(leds, NUM_LEDS); // Use this for WS2801 or APA102 72 | 73 | FastLED.setBrightness(max_bright); 74 | FastLED.setMaxPowerInVoltsAndMilliamps(5, 500); // FastLED Power management set at 5V, 500mA. 75 | 76 | } // setup() 77 | 78 | 79 | 80 | void loop() { 81 | 82 | 83 | EVERY_N_SECONDS(5) { // Change the palette every 5 seconds. 84 | for (int i = 0; i < 16; i++) { 85 | targetPalette[i] = CHSV(random8(), 255, 255); 86 | } 87 | } 88 | 89 | EVERY_N_MILLISECONDS(100) { // AWESOME palette blending capability once they do change. 90 | uint8_t maxChanges = 24; 91 | nblendPaletteTowardPalette(currentPalette, targetPalette, maxChanges); 92 | } 93 | 94 | 95 | EVERY_N_MILLIS_I(thistimer,20) { // For fun, let's make the animation have a variable rate. 96 | uint8_t timeval = beatsin8(10,20,50); // Use a sinewave for the line below. Could also use peak/beat detection. 97 | thistimer.setPeriod(timeval); // Allows you to change how often this routine runs. 98 | fadeToBlackBy(leds, NUM_LEDS, 16); // 1 = slow, 255 = fast fade. Depending on the faderate, the LED's further away will fade out. 99 | getSample(); 100 | agcAvg(); 101 | sndwave(); 102 | } 103 | 104 | FastLED.show(); 105 | 106 | } // loop() 107 | 108 | 109 | 110 | void getSample() { 111 | 112 | int16_t micIn; // Current sample starts with negative values and large values, which is why it's 16 bit signed. 113 | static long peakTime; 114 | 115 | micIn = analogRead(MIC_PIN); // Poor man's analog Read. 116 | micLev = ((micLev * 31) + micIn) / 32; // Smooth it out over the last 32 samples for automatic centering. 117 | micIn -= micLev; // Let's center it to 0 now. 118 | micIn = abs(micIn); // And get the absolute value of each sample. 119 | sample = (micIn <= squelch) ? 0 : (sample + micIn) / 2; // Using a ternary operator, the resultant sample is either 0 or it's a bit smoothed out with the last sample. 120 | sampleAvg = ((sampleAvg * 31) + sample) / 32; // Smooth it out over the last 32 samples. 121 | 122 | if (sample > (sampleAvg+maxVol) && millis() > (peakTime + 50)) { // Poor man's beat detection by seeing if sample > Average + some value. 123 | samplePeak = 1; // Then we got a peak, else we don't. Display routines need to reset the samplepeak value in case they miss the trigger. 124 | peakTime=millis(); 125 | } 126 | 127 | } // getSample() 128 | 129 | 130 | void agcAvg() { // A simple averaging multiplier to automatically adjust sound sensitivity. 131 | 132 | multAgc = (sampleAvg < 1) ? targetAgc : targetAgc / sampleAvg; // Make the multiplier so that sampleAvg * multiplier = setpoint 133 | sampleAgc = sample * multAgc; 134 | if (sampleAgc > 255) sampleAgc = 255; 135 | 136 | //------------ Oscilloscope output --------------------------- 137 | // Serial.print(targetAgc); Serial.print(" "); 138 | // Serial.print(multAgc); Serial.print(" "); 139 | // Serial.print(sampleAgc); Serial.print(" "); 140 | 141 | // Serial.print(micLev); Serial.print(" "); 142 | // Serial.print(sample); Serial.println(" "); 143 | // Serial.print(sampleAvg); Serial.print(" "); 144 | // Serial.print(samplePeak); Serial.print(" "); samplePeak = 0; 145 | // Serial.print(100); Serial.print(" "); 146 | // Serial.print(0); Serial.print(" "); 147 | // Serial.println(" "); 148 | 149 | } // agcAvg() 150 | 151 | 152 | 153 | void sndwave() { 154 | 155 | leds[NUM_LEDS/2] = ColorFromPalette(currentPalette, sampleAgc, sampleAgc, currentBlending); // Put the sample into the center 156 | 157 | for (int i = NUM_LEDS - 1; i > NUM_LEDS/2; i--) { //move to the left // Copy to the left, and let the fade do the rest. 158 | leds[i] = leds[i - 1]; 159 | } 160 | 161 | for (int i = 0; i < NUM_LEDS/2; i++) { // move to the right // Copy to the right, and let the fade to the rest. 162 | leds[i] = leds[i + 1]; 163 | } 164 | 165 | } // sndwave() 166 | --------------------------------------------------------------------------------