Task #1: Test the NeoPixel
I connected the NeoPixel Led strip to my Arduino and then tested the Blink example with the following code. And the first light blinked in red light, suggesting that the NeoPixel Led is working and functioning right and then I can proceed to the next task.
#include <FastLED.h> // How many leds in your strip? #define NUM_LEDS 1 // For led chips like WS2812, which have a data line, ground, and power, you just // need to define DATA_PIN. For led chipsets that are SPI based (four wires - data, clock, // ground, and power), like the LPD8806 define both DATA_PIN and CLOCK_PIN // Clock pin only needed for SPI based chipsets when not using hardware SPI #define DATA_PIN 3 #define CLOCK_PIN 13 // Define the array of leds CRGB leds[NUM_LEDS]; void setup() { // Uncomment/edit one of the following lines for your leds arrangement. // ## Clockless types ## FastLED.addLeds<NEOPIXEL, DATA_PIN>(leds, NUM_LEDS); // GRB ordering is assumed // FastLED.addLeds<SM16703, DATA_PIN, RGB>(leds, NUM_LEDS); // FastLED.addLeds<TM1829, DATA_PIN, RGB>(leds, NUM_LEDS); // FastLED.addLeds<TM1812, DATA_PIN, RGB>(leds, NUM_LEDS); // FastLED.addLeds<TM1809, DATA_PIN, RGB>(leds, NUM_LEDS); // FastLED.addLeds<TM1804, DATA_PIN, RGB>(leds, NUM_LEDS); // FastLED.addLeds<TM1803, DATA_PIN, RGB>(leds, NUM_LEDS); // FastLED.addLeds<UCS1903, DATA_PIN, RGB>(leds, NUM_LEDS); // FastLED.addLeds<UCS1903B, DATA_PIN, RGB>(leds, NUM_LEDS); // FastLED.addLeds<UCS1904, DATA_PIN, RGB>(leds, NUM_LEDS); // FastLED.addLeds<UCS2903, DATA_PIN, RGB>(leds, NUM_LEDS); // FastLED.addLeds<WS2812, DATA_PIN, RGB>(leds, NUM_LEDS); // GRB ordering is typical // FastLED.addLeds<WS2852, DATA_PIN, RGB>(leds, NUM_LEDS); // GRB ordering is typical // FastLED.addLeds<WS2812B, DATA_PIN, RGB>(leds, NUM_LEDS); // GRB ordering is typical // FastLED.addLeds<GS1903, DATA_PIN, RGB>(leds, NUM_LEDS); // FastLED.addLeds<SK6812, DATA_PIN, RGB>(leds, NUM_LEDS); // GRB ordering is typical // FastLED.addLeds<SK6822, DATA_PIN, RGB>(leds, NUM_LEDS); // FastLED.addLeds<APA106, DATA_PIN, RGB>(leds, NUM_LEDS); // FastLED.addLeds<PL9823, DATA_PIN, RGB>(leds, NUM_LEDS); // FastLED.addLeds<SK6822, DATA_PIN, RGB>(leds, NUM_LEDS); // FastLED.addLeds<WS2811, DATA_PIN, RGB>(leds, NUM_LEDS); // FastLED.addLeds<WS2813, DATA_PIN, RGB>(leds, NUM_LEDS); // FastLED.addLeds<APA104, DATA_PIN, RGB>(leds, NUM_LEDS); // FastLED.addLeds<WS2811_400, DATA_PIN, RGB>(leds, NUM_LEDS); // FastLED.addLeds<GE8822, DATA_PIN, RGB>(leds, NUM_LEDS); // FastLED.addLeds<GW6205, DATA_PIN, RGB>(leds, NUM_LEDS); // FastLED.addLeds<GW6205_400, DATA_PIN, RGB>(leds, NUM_LEDS); // FastLED.addLeds<LPD1886, DATA_PIN, RGB>(leds, NUM_LEDS); // FastLED.addLeds<LPD1886_8BIT, DATA_PIN, RGB>(leds, NUM_LEDS); // ## Clocked (SPI) types ## // FastLED.addLeds<LPD6803, DATA_PIN, CLOCK_PIN, RGB>(leds, NUM_LEDS); // GRB ordering is typical // FastLED.addLeds<LPD8806, DATA_PIN, CLOCK_PIN, RGB>(leds, NUM_LEDS); // GRB ordering is typical // FastLED.addLeds<WS2801, DATA_PIN, CLOCK_PIN, RGB>(leds, NUM_LEDS); // FastLED.addLeds<WS2803, DATA_PIN, CLOCK_PIN, RGB>(leds, NUM_LEDS); // FastLED.addLeds<SM16716, DATA_PIN, CLOCK_PIN, RGB>(leds, NUM_LEDS); // FastLED.addLeds<P9813, DATA_PIN, CLOCK_PIN, RGB>(leds, NUM_LEDS); // BGR ordering is typical // FastLED.addLeds<DOTSTAR, DATA_PIN, CLOCK_PIN, RGB>(leds, NUM_LEDS); // BGR ordering is typical // FastLED.addLeds<APA102, DATA_PIN, CLOCK_PIN, RGB>(leds, NUM_LEDS); // BGR ordering is typical // FastLED.addLeds<SK9822, DATA_PIN, CLOCK_PIN, RGB>(leds, NUM_LEDS); // BGR ordering is typical } void loop() { // Turn the LED on, then pause leds[0] = CRGB::Red; FastLED.show(); delay(500); // Now turn the LED off, then pause leds[0] = CRGB::Black; FastLED.show(); delay(500); }
Task #2: Use your computer to light up NeoPixels
Then, I installed the SerialRecord library provided by Oliver Steele and then copied the code HERE and pasted to my own sketch. I tried to send “1,255,0,100″ by pressing “CMD + Enter” and then the second Led lit up as I expected for the first time but I failed to capture it and I had to move onto the next step for the lack of time. So the video below can only show you a failed attempt of trying to light up the Led with the Serial Port. Probably it’s because I opened more than one Serial Ports, anyway, it returned back to normal after I closed everything else.
The code:
/* This is a code example for Arduino, to be used on Recitation 7 You need to have installed SerialRecord and FastLED libraries. It requires NeoPixel WS2812 at pin 3 Interaction Lab IMA NYU Shanghai 2022 Fall */ #include "SerialRecord.h" #include <FastLED.h> #define NUM_LEDS 60 // How many leds in your strip? #define DATA_PIN 3 // Which pin are you connecting Arduino to Data In? CRGB leds[NUM_LEDS]; // Change this number to the number of values you want to receive SerialRecord reader(4); void setup() { Serial.begin(9600); FastLED.addLeds<NEOPIXEL, DATA_PIN>(leds, NUM_LEDS); // Initialize FastLED.setBrightness(10); // BEWARE: external power for full (255) //further info at https://learn.adafruit.com/adafruit-neopixel-uberguide/powering-neopixels } void loop() { if (reader.read()) { int n = reader[0]; int r = reader[1]; int g = reader[2]; int b = reader[3]; leds[reader[0]] = CRGB(reader[1], reader[2], reader[3]); // Prepare the color information using CRGB( Red, Green, Blue FastLED.show(); // Pass the information of color to the LED } }
After that, I downloaded THIS sketch and when I click on the screen, the square where my “mouseX” is lights up with random colors and then the according Led lights up with the same color. And below is a video showing that amazing function.
Task #3: Add Music!
I downloaded the sketch that plays the music HERE and then replaced the original audio with another one that I got from searching songs from a singer I like from THIS website.
Then I tried to merge the two codes in Processing together. I wanted to keep both the function of the size change with the amplitude and the function of lighting the Led with accordance to where I click on the screen, so I first replaced the little squares with the circles in the second code that can change its size according to the loudness of the music. But I found the circles were always missing one side, creating a “crescent” shape in a row. So then I can up with an idea that I can probably change the circles into rectangles that changes their heights with accordance to the amplitude. And below is the version with rectangles only:
However, I think this effect was too simple and also the colors was not satisfying, either. So then I thought about changing the background using millis(), but then when I was trying out that change, something else strange happened and I also recorded that, even when I didn’t included the change using millis().
As I failed to use millis() to change the background, I thought that probably I can change the light effects by changing the colors of the “popping rectangles” manually. And I wanted the colors of shapes and also the Led colors to be white if I tap on any key, but turing random colors if I press the mouse. In this way, I can control when to make the lights all white and when to make the Led appear in different random colors. So here’s what I got as a final project:
In this version, I also included the circles in a row so that the two rectangle row and the circle amplifies the effect and colors the full screen, making the watching experience more enjoyable with the beautiful music.
The code:
/* This is a code example for Processing, to be used on Recitation 7 You need to have installed the SerialRecord library. Interaction Lab IMA NYU Shanghai 2022 Fall */ import processing.sound.*; import processing.serial.*; import osteele.processing.SerialRecord.*; Serial serialPort; SerialRecord serialRecord; SoundFile sample; Amplitude analysis; int W; //width of the tiles int NUM = 60; //amount of pixels int[r] = new int[NUM]; //red of each tile int[g] = new int[NUM]; //red of each tile int[b] = new int[NUM]; //red of each tile void setup() { fullScreen(); frameRate(10); size(640, 480); W = width/NUM; // load and play a sound file in a loop sample = new SoundFile(this, "2.mp3"); sample.loop(); // create the Amplitude analysis object analysis = new Amplitude(this); // analyze the playing sound file analysis.input(sample); // You can use this syntax and change COM3 for your serial port // printArray(Serial.list()); // serialPort = new Serial(this, "COM3", 9600); // in MacOS it looks like "/dev/cu.usbmodem1101" //or you can try to use this instead: String serialPortName = SerialUtils.findArduinoPort(); serialPort = new Serial(this, serialPortName, 9600); serialRecord = new SerialRecord(this, serialPort, 4); serialRecord.logToCanvas(false); rectMode(CENTER); } void draw() { background(240); // analyze the audio for its volume level float volume = analysis.analyze(); // volume is a number between 0.0 and 1.0 // map the volume value to a useful scale float diameter = map(volume, 0, 1, 0, width); for (int i=0; i<NUM; i ++) { fill(r[i], g[i], b[i], 140); circle(i * W + W/2, height/2, diameter/1.5); rect(i * W + W/2, width/8, diameter/1.8, diameter/1.8); fill(r[i], g[i], b[i], 140); rect(i * W + W/2, width/1.85, diameter/1.8, diameter/1.8); } } void mousePressed() { int n = floor(constrain(mouseX/W, 0, NUM-1)); r[n] = floor(random(70)); g[n] = floor(random(80)); b[n] = floor(random(255)); serialRecord.values[0] = n; // which pixel we change (0-59) serialRecord.values[1] = r[n]; // how much red (0-255) serialRecord.values[2] = g[n]; // how much green (0-255) serialRecord.values[3] = b[n]; // how much blue (0-255) serialRecord.send(); // send it! } void keyPressed(){ int N = floor(constrain(mouseX/W, 0, NUM-1)); r[N] = floor(255); g[N] = floor(255); b[N] = floor(255); serialRecord.values[0] = N; // which pixel we change (0-59) serialRecord.values[1] = r[N]; // how much red (0-255) serialRecord.values[2] = g[N]; // how much green (0-255) serialRecord.values[3] = b[N]; // how much blue (0-255) serialRecord.send(); // send it! }
Using FFT Analysis
I wanted to use this function because it seems so cool to have all that visualization of both changes in amplitude and frequency. And i also used what Professor Minsky taught us on class, which is using countless lines to paint the background between two gradually-changing colors.
And this is what it looks like:
The code: (I was in fact inspired by the fullScreen effect from this code and then I added that effect to the former one before this.)
//Variant of the FFTSpectrum example from Processing Foundation's Sound Library Examples //Parameters of display tweaked to best display frequency range by IMA Ix 2021 /** * This sketch shows how to use the FFT class to analyze a stream * of sound. Change the number of bands to get more spectral bands * (at the expense of more coarse-grained time resolution of the spectrum). */ import processing.sound.*; // Declare the sound source and FFT analyzer variables SoundFile sample; FFT fft; // Define how many FFT bands to use (this needs to be a power of two) int bands = 1024; // Define a smoothing factor which determines how much the spectrums of consecutive // points in time should be combined to create a smoother visualisation of the spectrum. // A smoothing factor of 1.0 means no smoothing (only the data from the newest analysis // is rendered), decrease the factor down towards 0.0 to have the visualisation update // more slowly, which is easier on the eye. float smoothingFactor = 0.2; // Create a vector to store the smoothed spectrum data in float[] sum = new float[bands]; // Variables for drawing the spectrum: // Declare a scaling factor for adjusting the height of the rectangles int scale = 10; // Declare a drawing variable for calculating the width of the bars float barWidth; void setup() { fullScreen(); background(255); // Calculate the width of the rects depending on how many frequency bands we have barWidth = 10*width/float(bands); // Load and play a soundfile and loop it. sample = new SoundFile(this, "2.mp3"); sample.loop(); // Create the FFT analyzer and connect the playing soundfile to it. fft = new FFT(this, bands); fft.input(sample); } void draw() { // Set background color, noStroke and fill color for (int j= 0; j<height; j++) { line(0, j, width, j); float c = map (j, 0, height, 0, 255); stroke(220, c, 100); } fill(255, 180); noStroke(); // Perform the analysis fft.analyze(); for (int i = 0; i < bands; i++) { // Smooth the FFT spectrum data by smoothing factor sum[i] += (fft.spectrum[i] - sum[i]) * smoothingFactor; // Draw the rectangles, adjust their height using the scale factor rect(i*barWidth, height, barWidth, -sum[i]*height*scale); } }