I have my Neopixel matrix spectrum analyzer functioning, but my main problem is that once the value in a bin is displayed on the LED matrix column, it disappears instantly once there is no longer a value in that bin. This results in a really "snappy" display, if you played a certain frequency for a split second, the corresponding column would briefly light up then completely turn off.
I'm hoping for some suggestions for my code such that in a column, once the LEDs turn on to display a value in a frequency bin, the LEDs will then turn off one at a time down the column. For example, if 8 LEDs in a column are turned on, and the next value in the bin says 5 LEDs should be turned on, then the LEDs will turn off one by one until 5 LEDs are left on.
This is exactly what I'm trying to replicate: if the video is slowed down, when observing any column, the LEDs do not turn off immediately, but rather the "height" of the column slowly decreases.
#define LIN_OUT 1 // use the log output function
#define FFT_N 256 // set to 256 point fft
#define DC_OFFSET 511
#define SAMPLING_FREQ (16000000/(13*32))
#include <FFT.h> //FFT library
#include <FastLED.h> //FastLED library
#define LED_DT 6 //LED data pin
#define COLOR_ORDER GRB //WS2812b specific
#define LED_TYPE WS2812B
#define NUM_LEDS 288 //Number of LEDs in project
#define COL_HEIGHT 9 //height of column
struct CRGB leds[NUM_LEDS];
float factors[32] = {0.65, 0.65, 0.7, 0.75, 0.75, 0.75,
0.75, 0.75, 0.8, 0.8, 0.8, 0.9,
1, 1, 1, 1, 1, 1,
1.1, 1.1, 1.15, 1.15, 1.15, 1.15,
1.15, 1.2, 1.25, 1.25, 1.3, 1.3, 1.3, 1.3};
int adc_val;
const uint8_t Height = 32; //width
const uint8_t Width = 9; //height
void setup() {
delay(1000); //soft startup to ease flow of electrons
LEDS.addLeds<LED_TYPE, LED_DT, COLOR_ORDER>(leds, NUM_LEDS);
FastLED.setBrightness(100);
TIMSK0 = 0; // turn off timer0 for lower jitter - delay() and millis() killed
ADCSRA = 0xe5; // set the adc to free running mode
ADMUX = 0x40; // use adc0
DIDR0 = 0x01; // turn off the digital input for adc0
}
void loop() {
while (1) { // reduces jitter
cli(); // UDRE interrupt slows this way down on arduino1.0
for (int i = 0 ; i < 512 ; i += 2) { // save 256 samples
while (!(ADCSRA & 0x10)); // wait for adc to be ready
ADCSRA = 0xf5; // restart adc
byte m = ADCL; // fetch adc data
byte j = ADCH;
int k = (j << 8) | m; // form into an int
k -= DC_OFFSET;
adc_val = k<<6;
fft_input[i] = adc_val; // put real data into even bins
fft_input[i + 1] = 0; // set odd bins to 0
}
// window data, then reorder, then run, then take output
fft_window(); // window the data for better frequency response
fft_reorder(); // reorder the data before doing the fft
fft_run(); // process the data in the fft
fft_mag_lin(); // take the output of the fft
sei(); // turn interrupts back on
fft_lin_out[1] -= 10; //adjust for values in bin when silent (unknown cause)
uint32_t ms = millis();
int32_t yHueDelta32 = ((int32_t)cos16( ms * 27 ) * (350 / Width));
int32_t xHueDelta32 = ((int32_t)cos16( ms * 39 ) * (310 / Height));
fftDisplay(ms / 65536, yHueDelta32 / 32768, xHueDelta32 / 32768);
FastLED.show();
}
}
void fftDisplay(byte startHue8, int8_t yHueDelta8, int8_t xHueDelta8) {
byte lineStartHue = startHue8;
unsigned char i, yVal, colHeight;
for(i = 0; i < 32; i++)
{
colHeight = map((unsigned char)fft_lin_out[i+1], 0, 235, 0, 9);
colHeight = colHeight * factors[i];
lineStartHue += yHueDelta8;
byte pixelHue = lineStartHue;
for(yVal = 0; yVal < COL_HEIGHT; yVal++)
{
pixelHue += xHueDelta8;
if(yVal <= colHeight && colHeight != 0)
leds[XY(i, yVal)] = CHSV( pixelHue, 255, 255);
else
leds[XY(i, yVal)] = CRGB::Black;
}
}
}
uint16_t XY(uint8_t y, uint8_t x)
{
uint16_t i;
if(y & 0x01) {
// Odd rows run backwards
uint8_t reverseX = (Width - 1) - x;
i = (y * Width) + reverseX;
} else {
// Even rows run forwards
i = (y * Width) + x;
}
return i;
}
