Crazy Bug o(╥﹏╥)o
The recitation for this week was a little bit messy. I mean, really messy. I went over the recitation files before class but I never expected the bug that I was going to encounter. SerialRecord was not, is not, and will not be a friend of mine.
During the recitation, I advanced fast and started step 2, where we were asked to use serial monitor to control the LEDs. Well, the numbers that I typed into the computer didn’t function as I expected. There was a line of warning in the console, for which I looked the whole afternoon within the library and found it to be a mild compilation error that does not matter at all. I also tried deleting the library automatically and manually, installing the same library but different versions of it, and reinstalling arduino idle.
Something that I noticed along the process, is that, how fast I plugged the USB into the port would result in different but rather consistent reader[0] value, as you can see in the photos attached, where the reader[0] value were printed out in the console. What I mean by consistent is, that fast plugging resulted in a much greater value whereas, slower plugging resulted in a smaller one. Their difference in magnitude is around the level of 10^1. Combined with the fast and slow plugging, it reminded me of USB3.0 verses USB2.0. Faster and slower plugging will make the system identified the port differently. Well, the hypothesis didn’t help at all. Uncanny, it was, for a downstream output to inversely affect the upstream. I failed to figure the problem out, but I highly suspect to be the problem with the hardware or the protocol running on the ports. The code, as well as the environment, were excluded from suspicion, since I didn’t find relevant error in the library.
Make it happen! (*^▽^*)
Alternatviely, I tried to run the program on Ruili’s macbook instead. Though she also ran into some other problems with the baudrate and lagging and weird problem, her reader[0] has been giving out the correct value. So, I tried. Unfortunately, it didn’t work. I completely lost my mind. What I mean by it didn’t work, is, that even the sample code could not work as before.
Nevermind the silly bug, I figured it out by borrowing a new computer from the equipment room. Simple and neat solution, got everything done. I took the void function that I did in the recitation6 and adapted to the visual. Considering the problem of perspective, I changed the circle() function into ellipse(). To avoid serialrecord overload problem at best, I decided to sent only one digit, once a while, through using
while (frameCount%10==1) {
// curve up the volume to fit the non-linear manner in which humans perceive light and color
serialRecord.values[0] = floor(map(sqrt(volume), 0, 1, 0, 59));
serialRecord.send(); // send it!
break;
}
For the LEDs, I used neoPixel library instead of fastPixel, because I had plenty experience working with the former one thanks to the midterm, plus it provides much stronger and integrated functions than the latter one. The idea was simple as well. Processing sent over the number of pixels ought to lit according to the volume analysis, what the microcontroller had to do was simply lighting up exactly the same number of pixels as requested, each with an increasing brightness according to their sequence. Always keep in mind that if no update is given to a pixel, then it will maintain its original state until a new signal is sent over telling it what to do. So, let’s say, the volume is going down, for the pixels to shrink in number, an extra line of code should be added to clear out the rest of pixels, otherwise we won’t see a change; but for the volume going up, there’s no such concern. The solution is trivial.
if (reader.read()) {
volume = reader[0];
if (volume != prevolume) {
pixels.fill(1, volume+1); // fill from the volume to default the last pixel
pixels.show();
for (int n=0; n<=volume; n++) {
pixels.setPixelColor(n, pixels.ColorHSV(33132, 194, map(n, 0, 60, 0, 100)));
pixels.show();
delay(10);
}
}
prevolume = volume;
}
Full code for reference (p≧w≦q)
Processing
import processing.sound.*;
import processing.serial.*;
import osteele.processing.SerialRecord.*;
PImage img;
float volume_pre = 0, volume_now = 0, deg = 0, Radius = 0;
float volume;
SoundFile sample;
Amplitude analysis;
Serial serialPort;
SerialRecord serialRecord;
int NUM = 60; //amount of pixels
void setup() {
img = loadImage("backdrop.jpg");
frameRate(60);
size(1080, 720);
// load and play a sound file in a loop
sample = new SoundFile(this, "Hans Zimmer - Herald of the Change.mp3");
sample.loop();
// create the Amplitude analysis object
analysis = new Amplitude(this);
// analyze the playing sound file
analysis.input(sample);
String serialPortName = SerialUtils.findArduinoPort();
serialPort = new Serial(this, serialPortName, 9600);
serialRecord = new SerialRecord(this, serialPort, 1);
//serialRecord.logToCanvas(false);
}
void draw() {
image(img, 0, 0);
colorMode(RGB, 255, 255, 255);
if (frameCount%300==0) {
tint(255, 255, 255, 100); // clean screen thoroughly once a while
println("fuck you");
}
else {
tint(255, 255, 255, 20); // fulfill a fade-out effect
}
noStroke();
println(frameRate); // check running status
//println(analysis.analyze());
// analyze the audio for its volume level
volume = analysis.analyze();
while (frameCount%10==1) {
// curve up the volume to fit the non-linear manner in which humans perceive light and color
serialRecord.values[0] = floor(map(sqrt(volume), 0, 1, 0, 59));
serialRecord.send(); // send it!
break;
}
// display visuals only if a difference in volume occurs
if (abs(volume - volume_pre) > 0.01) {
// change the radius and range of leds once a while, avoid jumpy
while (frameCount%15==1) {
//serialRecord.values[0] = floor(map(sqrt(volume), 0, 1, 0, 59));
//serialRecord.send(); // send it!
// store the value to another container, get ready for another iteration
volume_now = volume_pre;
volume_pre = volume;
break;
}
}
// create animated circles
circleLeft(width/2, height/2, width/2, height/2, floor(map(sqrt(volume_now), 0, 1, 0, width)), floor(map(sqrt(volume_pre), 0, 1, 0, width)));
}
void circleLeft(float x_up, float y_up, float x_down, float y_down, int size_up, int size_down) {
noFill();
// color
colorMode(HSB, 360, 100, 100);
//stroke(288, 64, map(volume, 0, 1, 80, 100));
stroke(#5ED1FF);
//strokeWeight(1);
//strokeWeight(map(cos(deg), -1, 1, 0.5, 1));
strokeWeight(map(volume_now, 0, 1, 0.5, 2));
Radius = map(cos(deg), -1, 1, 0, size_up);
ellipse(x_up, y_up, 1.7*Radius, 0.4*Radius);
deg += map(sqrt(volume_pre), 0, 1, 0.005, 0.01);
delay(20);
noFill();
// color
//stroke(332, 90, map(volume, 0, 1, 80, 100));
stroke(#31c2c8);
//strokeWeight(2);
//strokeWeight((map(cos(deg), -1, 1, 0.5, 1)));
strokeWeight(map(volume_now, 0, 1, 0.5, 2));
Radius = map(-cos(deg), -1, 1, 0, size_down);
ellipse(x_down, y_down, 1.7*Radius, 0.4*Radius);
//delay(20);
}
Arduino
#include "SerialRecord.h"
#include <Adafruit_NeoPixel.h>
#ifdef __AVR__
#include <avr/power.h> // Required for 16 MHz Adafruit Trinket
#endif
// How many NeoPixels are attached to the Arduino?
#define NUMPIXELS 60 // Popular NeoPixel ring size
// Which pin on the Arduino is connected to the NeoPixels?
#define PIN 6 // On Trinket or Gemma, suggest changing this to 1CRGB leds[NUM_LEDS];
// When setting up the NeoPixel library, we tell it how many pixels,
// and which pin to use to send signals. Note that for older NeoPixel
// strips you might need to change the third parameter -- see the
// strandtest example for more information on possible values.
Adafruit_NeoPixel pixels(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);
int volume, prevolume;
// Change this number to the number of values you want to receive
SerialRecord reader(1);
void setup() {
Serial.begin(9600);
// These lines are specifically to support the Adafruit Trinket 5V 16 MHz.
// Any other board, you can remove this part (but no harm leaving it):
#if defined(__AVR_ATtiny85__) && (F_CPU == 16000000)
clock_prescale_set(clock_div_1);
#endif
// END of Trinket-specific code.
pixels.begin(); // INITIALIZE NeoPixel strip object (REQUIRED)
}
void loop() {
delay(100);
if (reader.read()) {
volume = reader[0];
if (volume != prevolume) {
pixels.fill(1, volume); // fill from the volume to default the last pixel
pixels.show();
for (int n=0; n<=volume; n++) {
pixels.setPixelColor(n, pixels.ColorHSV(33132, 194, map(n, 0, 60, 0, 100)));
// pixels.setBrightness(map(n, 0, 60, 0, 255));
pixels.show();
delay(10);
}
}
prevolume = volume;
}
}
Leave a Reply