偶然心血来潮,想要做一个声音可视化的系列专题。这个专题的难度有点高,涉及面也比较广泛,相关的FFT和FHT等算法也相当复杂,不过还是打算从最简单的开始,实际动手做做试验,耐心尝试一下各种方案,逐步积累些有用的音乐频谱可视化的资料,也会争取成型一些实用好玩的音乐可视器项目。
造物记
【花雕动手做】有趣好玩的音乐可视化项目(01)---LED节奏灯
https://makelog.dfrobot.com.cn/article-311363.html
【花雕动手做】有趣好玩的音乐可视化项目(02)---OLED频谱灯
https://makelog.dfrobot.com.cn/article-311365.html
【花雕动手做】有趣好玩的音乐可视化项目(03)---RGB律动灯
https://makelog.dfrobot.com.cn/article-311366.html
【花雕动手做】有趣好玩的音乐可视化项目(04)---WS2812条灯
https://makelog.dfrobot.com.cn/article-311377.html
【花雕动手做】有趣好玩的音乐可视化项目(05)---WS2812柱跳灯
https://makelog.dfrobot.com.cn/article-311378.html
【花雕动手做】有趣好玩的音乐可视化项目(06)---点阵频谱灯
https://makelog.dfrobot.com.cn/article-311379.html
【花雕动手做】有趣好玩的音乐可视化系列小项目(07)---大方格频谱灯
https://makelog.dfrobot.com.cn/article-311429.html
【花雕动手做】有趣好玩的音乐可视化系列小项目(08)---四位32段点阵屏
https://makelog.dfrobot.com.cn/article-311463.html
【花雕动手做】有趣好玩的音乐可视化系列小项目(09)---X Music Spectrum
https://makelog.dfrobot.com.cn/article-311482.html
【花雕动手做】有趣好玩的音乐可视化系列小项目(10)---WS2812硬板屏
https://makelog.dfrobot.com.cn/article-311491.html
【花雕动手做】有趣好玩的音乐可视化项目(11)---WS2812幻彩灯带
https://makelog.dfrobot.com.cn/article-311745.html
【花雕动手做】有趣好玩的音乐可视化项目(12)---米管快速节奏灯
https://makelog.dfrobot.com.cn/article-311746.html
【花雕动手做】有趣好玩的音乐可视化系列小项目(13)---有机棒立柱灯
https://makelog.dfrobot.com.cn/article-311759.html
【花雕动手做】有趣好玩的音乐可视化系列小项目(10)---WS2812硬板屏
WS2812B主要特点
智能反接保护,电源反接不会损坏IC。
IC控制电路与LED点光源公用一个电源。
控制电路与RGB芯片集成在一个5050封装的元器件中,构成一个完整的外控像素点。
内置信号整形电路,任何一个像素点收到信号后经过波形整形再输出,保证线路波形畸变不会累加。
内置上电复位和掉电复位电路。
每个像素点的三基色颜色可实现256级亮度显示,完成16777216种颜色的全真色彩显示,扫描频率不低于400Hz/s。
串行级联接口,能通过一根信号线完成数据的接收与解码。
任意两点传传输距离在不超过5米时无需增加任何电路。
当刷新速率30帧/秒时,级联数不小于1024点。
数据发送速度可达800Kbps。
光的颜色高度一致,性价比高。
主要应用领域
LED全彩发光字灯串,LED全彩模组, LED全彩软灯条硬灯条,LED护栏管。
LED点光源,LED像素屏,LED异形屏,各种电子产品,电器设备跑马灯。
WS2812模块电原理图
MAX9814
是一款低成本高性能麦克风放大器,具有自动增益控制(AGC)和低噪声麦克风偏置。器件具有低噪声前端放大器、可变增益放大(VGA)、输出放大器、麦克风偏置电压发生器和AGC控制电路。
●自动增益控制(AGC)
●3种增益设置(40dB、50dB、60dB)
●可编程动作时间
●可编程动作和释放时间比
●电源电压范围2.7V~5.5V
●低THD:0.04% (典型值)
●低功耗关断模式
●内置2V低噪声麦克风偏置
搜索并安装Adafruit_NeoPixel库:
【花雕动手做】有趣好玩的音乐可视化系列小项目(10)---WS2812硬板屏
项目之一:使用Adafruit_NeoPixel库的音乐可视化多彩节奏灯
实验开源代码
/*
【花雕动手做】有趣好玩的音乐可视化系列小项目(10)---WS2812硬板屏
项目之一:使用Adafruit_NeoPixel库的音乐可视化多彩节奏灯
*/
#include <Adafruit_NeoPixel.h>
#define MIC A0 // 麦克风与A0相连接
#define LED_PIN 6 // LED are connected to D6
#define N_PIXELS 16 // Number of LED
#define N 100 //样本数
#define fadeDelay 10 // 淡出量
#define noiseLevel 40 // 降噪下限
Adafruit_NeoPixel strip = Adafruit_NeoPixel(N_PIXELS, LED_PIN, NEO_GRB + NEO_KHZ800);
int samples[N]; // 存储样本
int periodFactor = 0; // 用于周期计算
int t1 = -1;
int T;
int slope;
byte periodChanged = 0;
void setup() {
// Serial.begin(9600);
strip.begin();
ledsOff();
delay(500);
displayColor(Wheel(100));
strip.show();
delay(500);
}
void loop() {
Samples();
}
void Samples() {
for (int i = 0; i < N; i++) {
samples[i] = analogRead(0);
if (i > 0) {
slope = samples[i] - samples[i - 1];
}
else {
slope = samples[i] - samples[N - 1];
}
if (abs(slope) > noiseLevel) {
if (slope < 0) {
calculatePeriod(i);
if (periodChanged == 1) {
displayColor(getColor(T));
}
}
}
else {
ledsOff();
}
periodFactor += 1;
delay(1);
}
}
void calculatePeriod(int i) {
if (t1 == -1) {
t1 = i;
}
else {
int period = periodFactor * (i - t1);
periodChanged = T == period ? 0 : 1;
T = period;
// Serial.println(T);
t1 = i;
periodFactor = 0;
}
}
uint32_t getColor(int period) {
if (period == -1)
return Wheel(0);
else if (period > 400)
return Wheel(5);
else
return Wheel(map(-1 * period, -400, -1, 50, 255));
}
void fadeOut()
{
for (int i = 0; i < 5; i++) {
strip.setBrightness(110 - i * 20);
strip.show(); // Update strip
delay(fadeDelay);
periodFactor += fadeDelay;
}
}
void fadeIn() {
strip.setBrightness(100);
strip.show();
for (int i = 0; i < 5; i++) {
//strip.setBrightness(20*i + 30);
//strip.show();
delay(fadeDelay);
periodFactor += fadeDelay;
}
}
void ledsOff() {
fadeOut();
for (int i = 0; i < N_PIXELS; i++) {
strip.setPixelColor(i, 0, 0, 0);
}
}
void displayColor(uint32_t color) {
for (int i = 0; i < N_PIXELS; i++) {
strip.setPixelColor(i, color);
}
fadeIn();
}
uint32_t Wheel(byte WheelPos) {
// Serial.println(WheelPos);
if (WheelPos < 85) {
return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
}
else if (WheelPos < 170) {
WheelPos -= 85;
return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3);
}
else {
WheelPos -= 170;
return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3);
}
}
实验场景图
【花雕动手做】有趣好玩的音乐可视化系列小项目(10)---WS2812硬板屏
项目之一:使用Adafruit_NeoPixel库的多彩节奏灯
实验视频剪辑
https://v.youku.com/v_show/id_XNTgyNzM2MTM2NA==.html?spm=a2hcb.playlsit.page.1
【花雕动手做】有趣好玩的音乐可视化系列小项目(10)---WS2812硬板屏
项目之二:音乐反应式 LED 灯板(4x4位)
实验开源代码
/*
【花雕动手做】有趣好玩的音乐可视化系列小项目(10)---WS2812硬板屏
项目之二:音乐反应式 LED 灯板
*/
#include <Adafruit_NeoPixel.h>
#include <math.h>
#define N_PIXELS 16
#define MIC_PIN A0
#define LED_PIN 6
#define SAMPLE_WINDOW 4
#define PEAK_HANG 24
#define PEAK_FALL 4
#define INPUT_FLOOR 10
#define INPUT_CEILING 50
byte peak = 16;
unsigned int sample;
byte Count = 0;
byte HangCount = 0;
Adafruit_NeoPixel strip = Adafruit_NeoPixel(N_PIXELS, LED_PIN, NEO_GRB + NEO_KHZ800);
void setup() {
Serial.begin(9600);
analogReference(EXTERNAL);
strip.setBrightness(22);
strip.show();
strip.begin();
}
float fscale( float originalMin, float originalMax, float newBegin, float newEnd, float inputValue, float curve) {
float OriginalRange = 0;
float NewRange = 0;
float zeroRefCurVal = 0;
float normalizedCurVal = 0;
float rangedValue = 0;
boolean invFlag = 0;
if (curve > 10) curve = 10;
if (curve < -10) curve = -10;
curve = (curve * -.1) ;
curve = pow(10, curve);
if (inputValue < originalMin) {
inputValue = originalMin;
}
if (inputValue > originalMax) {
inputValue = originalMax;
}
OriginalRange = originalMax - originalMin;
if (newEnd > newBegin) {
NewRange = newEnd - newBegin;
}
else
{
NewRange = newBegin - newEnd;
invFlag = 1;
}
zeroRefCurVal = inputValue - originalMin;
normalizedCurVal = zeroRefCurVal / OriginalRange; // normalize to 0 - 1 float
Serial.print(OriginalRange, DEC);
Serial.print(" ");
Serial.print(NewRange, DEC);
Serial.print(" ");
Serial.println(zeroRefCurVal, DEC);
Serial.println();
delay(10);
if (originalMin > originalMax ) {
return 0;
}
if (invFlag == 0) {
rangedValue = (pow(normalizedCurVal, curve) * NewRange) + newBegin;
}
else
{
rangedValue = newBegin - (pow(normalizedCurVal, curve) * NewRange);
}
return rangedValue;
}
void loop() {
unsigned long startMillis = millis();
float peakToPeak = 0;
unsigned int signalMax = 0;
unsigned int signalMin = 1023;
unsigned int c, y;
while (millis() - startMillis < SAMPLE_WINDOW)
{
sample = analogRead(MIC_PIN);
if (sample < 1024)
{
if (sample > signalMax)
{
signalMax = sample;
}
else if (sample < signalMin)
{
signalMin = sample;
}
}
}
peakToPeak = signalMax - signalMin;
for (int i = 0; i <= strip.numPixels() - 1; i++) {
strip.setPixelColor(i, Wheel(map(i, 0, strip.numPixels() - 1, 30, 150)));
}
c = fscale(INPUT_FLOOR, INPUT_CEILING, strip.numPixels(), 0, peakToPeak, 2);
if (c < peak) {
peak = c;
HangCount = 0;
}
if (c <= strip.numPixels()) {
drawLine(strip.numPixels(), strip.numPixels() - c, strip.Color(0, 0, 0));
}
y = strip.numPixels() - peak;
strip.setPixelColor(y - 1, Wheel(map(y, 0, strip.numPixels() - 1, 30, 150)));
strip.show();
if (HangCount > PEAK_HANG) {
if (++Count >= PEAK_FALL) {
peak++;
Count = 0;
}
}
else {
HangCount++;
}
}
void drawLine(uint8_t from, uint8_t to, uint32_t c) {
uint8_t fromTemp;
if (from > to) {
fromTemp = from;
from = to;
to = fromTemp;
}
for (int i = from; i <= to; i++) {
strip.setPixelColor(i, c);
}
}
uint32_t Wheel(byte WheelPos) {
if (WheelPos < 85) {
return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
}
else if (WheelPos < 170) {
WheelPos -= 85;
return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3);
}
else {
WheelPos -= 170;
return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3);
}
}
【花雕动手做】有趣好玩的音乐可视化系列小项目(10)---WS2812硬板屏
项目之二:音乐反应式 LED 灯板(4x4位)
实验视频剪辑
https://v.youku.com/v_show/id_XNTgyNzQwNjIyOA==.html?spm=a2hcb.playlsit.page.1
实验场动态图
【花雕动手做】有趣好玩的音乐可视化系列小项目(10)---WS2812硬板屏
项目之三:六十四位闪动音乐频谱灯(8x8WS2812硬屏)
实验开源代码
/*
【花雕动手做】有趣好玩的音乐可视化系列小项目(10)---WS2812硬板屏
项目之三:六十四位闪动音乐频谱灯(8x8WS2812硬屏)
*/
#include "FastLED.h"
#define OCTAVE 1 // // Group buckets into octaves (use the log output function LOG_OUT 1)
#define OCT_NORM 0 // Don't normalise octave intensities by number of bins
#define FHT_N 256 // set to 256 point fht
#include <FHT.h> // include the library
//int noise[] = {204,188,68,73,150,98,88,68}; // noise level determined by playing pink noise and seeing levels [trial and error]{204,188,68,73,150,98,88,68}
// int noise[] = {204,190,108,85,65,65,55,60}; // noise for mega adk
int noise[] = {204, 195, 100, 90, 85, 80, 75, 75}; // noise for NANO
//int noise[] = {204,198,100,85,85,80,80,80};
float noise_fact[] = {15, 7, 1.5, 1, 1.2, 1.4, 1.7, 3}; // noise level determined by playing pink noise and seeing levels [trial and error]{204,188,68,73,150,98,88,68}
float noise_fact_adj[] = {15, 7, 1.5, 1, 1.2, 1.4, 1.7, 3}; // noise level determined by playing pink noise and seeing levels [trial and error]{204,188,68,73,150,98,88,68}
#define LED_PIN 6
#define LED_TYPE WS2812
#define COLOR_ORDER GRB
// Params for width and height
const uint8_t kMatrixWidth = 8;
const uint8_t kMatrixHeight = 8;//----------was 27
//#define NUM_LEDS (kMatrixWidth * kMatrixHeight)
#define NUM_LEDS 64
CRGB leds[NUM_LEDS];
int counter2 = 0;
void setup() {
Serial.begin(9600);
delay(1000);
FastLED.addLeds<LED_TYPE, LED_PIN, COLOR_ORDER>(leds, NUM_LEDS).setCorrection( TypicalLEDStrip );
FastLED.setBrightness (22);
fill_solid(leds, NUM_LEDS, CRGB::Black);
FastLED.show();
// TIMSK0 = 0; // turn off timer0 for lower jitter
ADCSRA = 0xe5; // set the adc to free running mode
ADMUX = 0x40; // use adc0
DIDR0 = 0x01; // turn off the digital input for adc0
}
void loop() {
int prev_j[8];
int beat = 0;
int prev_oct_j;
int counter = 0;
int prev_beat = 0;
int led_index = 0;
int saturation = 0;
int saturation_prev = 0;
int brightness = 0;
int brightness_prev = 0;
while (1) { // reduces jitter
cli(); // UDRE interrupt slows this way down on arduino1.0
for (int i = 0 ; i < FHT_N ; i++) { // 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 -= 0x0200; // form into a signed int
k <<= 6; // form into a 16b signed int
fht_input[i] = k; // put real data into bins
}
fht_window(); // window the data for better frequency response
fht_reorder(); // reorder the data before doing the fht
fht_run(); // process the data in the fht
fht_mag_octave(); // take the output of the fht fht_mag_log()
// every 50th loop, adjust the volume accourding to the value on A2 (Pot)
if (counter >= 50) {
ADMUX = 0x40 | (1 & 0x07); // set admux to look at Analogpin A1 - Master Volume
while (!(ADCSRA & 0x10)); // wait for adc to be ready
ADCSRA = 0xf5; // restart adc
delay(10);
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
float master_volume = (k + 0.1) / 1000 + .75; // so the valu will be between ~0.5 and 1.---------------------+.75 was .5
Serial.println (master_volume);
for (int i = 1; i < 8; i++) {
noise_fact_adj[i] = noise_fact[i] * master_volume;
}
ADMUX = 0x40 | (0 & 0x07); // set admux back to look at A0 analog pin (to read the microphone input
counter = 0;
}
sei();
counter++;
// End of Fourier Transform code - output is stored in fht_oct_out[i].
// i=0-7 frequency (octave) bins (don't use 0 or 1), fht_oct_out[1]= amplitude of frequency for bin 1
// for loop a) removes background noise average and takes absolute value b) low / high pass filter as still very noisy
// c) maps amplitude of octave to a colour between blue and red d) sets pixel colour to amplitude of each frequency (octave)
for (int i = 1; i < 8; i++) { // goes through each octave. skip the first 1, which is not useful
int j;
j = (fht_oct_out[i] - noise[i]); // take the pink noise average level out, take the asbolute value to avoid negative numbers
if (j < 10) {
j = 0;
}
j = j * noise_fact_adj[i];
if (j < 10) {
j = 0;
}
else {
j = j * noise_fact_adj[i];
if (j > 180) {
if (i >= 7) {
beat += 2;
}
else {
beat += 1;
}
}
j = j / 30;
j = j * 30; // (force it to more discrete values)
}
prev_j[i] = j;
// Serial.print(j);
// Serial.print(" ");
// this fills in 11 LED's with interpolated values between each of the 8 OCT values
if (i >= 2) {
led_index = 2 * i - 3;
prev_oct_j = (j + prev_j[i - 1]) / 2;
saturation = constrain(j + 50, 0, 255); //-----------50 was 30
saturation_prev = constrain(prev_oct_j + 50, 0, 255);
brightness = constrain(j, 0, 255);
brightness_prev = constrain(prev_oct_j, 0, 255);
if (brightness == 255) {
saturation = 50;
brightness = 200;
}
if (brightness_prev == 255) {
saturation_prev = 50;
brightness_prev = 200;
}
for (uint8_t y = 0; y < kMatrixHeight; y++) {
leds[XY(led_index - 1, y)] = CHSV(j + y * 30, saturation, brightness);
if (i > 2) {
prev_oct_j = (j + prev_j[i - 1]) / 2;
leds[ XY(led_index - 2, y)] = CHSV(prev_oct_j + y * 30, saturation_prev, brightness_prev);
}
}
}
}
if (beat >= 7) {
fill_solid(leds, NUM_LEDS, CRGB::Gray);
FastLED.setBrightness(200);
}
else {
if (prev_beat != beat) {
FastLED.setBrightness(40 + beat * beat * 5);
prev_beat = beat;
}
}
FastLED.show();
if (beat) {
counter2 += ((beat + 4) / 2 - 2);
if (counter2 < 0) {
counter2 = 1000;
}
if (beat > 3 && beat < 7) {
FastLED.delay (20);
}
beat = 0;
}
// Serial.println();
}
}
// Param for different pixel layouts
const bool kMatrixSerpentineLayout = false;
// Set 'kMatrixSerpentineLayout' to false if your pixels are
// laid out all running the same way, like this:
// Set 'kMatrixSerpentineLayout' to true if your pixels are
// laid out back-and-forth, like this:
uint16_t XY( uint8_t x, uint8_t y)
{
uint16_t i;
if ( kMatrixSerpentineLayout == false) {
i = (y * kMatrixWidth) + x;
}
if ( kMatrixSerpentineLayout == true) {
if ( y & 0x01) {
// Odd rows run backwards
uint8_t reverseX = (kMatrixWidth - 1) - x;
i = (y * kMatrixWidth) + reverseX;
} else {
// Even rows run forwards
i = (y * kMatrixWidth) + x;
}
}
i = (i + counter2) % NUM_LEDS;
return i;
}
【花雕动手做】有趣好玩的音乐可视化系列小项目(10)---WS2812硬板屏
项目之三:六十四位闪动音乐频谱灯(8x8位WS2812硬屏)
实验视频剪辑
https://v.youku.com/v_show/id_XNTgyNzExNzAyOA==.html?spm=a2hcb.playlsit.page.1
实验场景动态图
【花雕动手做】有趣好玩的音乐可视化系列小项目(10)---WS2812硬板屏
项目之四:256位全彩闪动音乐频谱灯(8x32位WS2812硬屏)
实验开源代码
/*
【花雕动手做】有趣好玩的音乐可视化系列小项目(10)---WS2812硬板屏
项目之三:六十四位闪动音乐频谱灯(8x8WS2812硬屏)
*/
#include "FastLED.h"
#define OCTAVE 1 // // Group buckets into octaves (use the log output function LOG_OUT 1)
#define OCT_NORM 0 // Don't normalise octave intensities by number of bins
#define FHT_N 256 // set to 256 point fht
#include <FHT.h> // include the library
//int noise[] = {204,188,68,73,150,98,88,68}; // noise level determined by playing pink noise and seeing levels [trial and error]{204,188,68,73,150,98,88,68}
// int noise[] = {204,190,108,85,65,65,55,60}; // noise for mega adk
int noise[] = {204, 195, 100, 90, 85, 80, 75, 75}; // noise for NANO
//int noise[] = {204,198,100,85,85,80,80,80};
float noise_fact[] = {15, 7, 1.5, 1, 1.2, 1.4, 1.7, 3}; // noise level determined by playing pink noise and seeing levels [trial and error]{204,188,68,73,150,98,88,68}
float noise_fact_adj[] = {15, 7, 1.5, 1, 1.2, 1.4, 1.7, 3}; // noise level determined by playing pink noise and seeing levels [trial and error]{204,188,68,73,150,98,88,68}
#define LED_PIN 6
#define LED_TYPE WS2812
#define COLOR_ORDER GRB
// Params for width and height
const uint8_t kMatrixWidth = 8;
const uint8_t kMatrixHeight = 32;//----------was 27
//#define NUM_LEDS (kMatrixWidth * kMatrixHeight)
#define NUM_LEDS 256
CRGB leds[NUM_LEDS];
int counter2 = 0;
void setup() {
Serial.begin(9600);
delay(1000);
FastLED.addLeds<LED_TYPE, LED_PIN, COLOR_ORDER>(leds, NUM_LEDS).setCorrection( TypicalLEDStrip );
FastLED.setBrightness (6);
fill_solid(leds, NUM_LEDS, CRGB::Black);
FastLED.show();
// TIMSK0 = 0; // turn off timer0 for lower jitter
ADCSRA = 0xe5; // set the adc to free running mode
ADMUX = 0x40; // use adc0
DIDR0 = 0x01; // turn off the digital input for adc0
}
void loop() {
int prev_j[8];
int beat = 0;
int prev_oct_j;
int counter = 0;
int prev_beat = 0;
int led_index = 0;
int saturation = 0;
int saturation_prev = 0;
int brightness = 0;
int brightness_prev = 0;
while (1) { // reduces jitter
cli(); // UDRE interrupt slows this way down on arduino1.0
for (int i = 0 ; i < FHT_N ; i++) { // 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 -= 0x0200; // form into a signed int
k <<= 6; // form into a 16b signed int
fht_input[i] = k; // put real data into bins
}
fht_window(); // window the data for better frequency response
fht_reorder(); // reorder the data before doing the fht
fht_run(); // process the data in the fht
fht_mag_octave(); // take the output of the fht fht_mag_log()
// every 50th loop, adjust the volume accourding to the value on A2 (Pot)
if (counter >= 50) {
ADMUX = 0x40 | (1 & 0x07); // set admux to look at Analogpin A1 - Master Volume
while (!(ADCSRA & 0x10)); // wait for adc to be ready
ADCSRA = 0xf5; // restart adc
delay(10);
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
float master_volume = (k + 0.1) / 1000 + .75; // so the valu will be between ~0.5 and 1.---------------------+.75 was .5
Serial.println (master_volume);
for (int i = 1; i < 8; i++) {
noise_fact_adj[i] = noise_fact[i] * master_volume;
}
ADMUX = 0x40 | (0 & 0x07); // set admux back to look at A0 analog pin (to read the microphone input
counter = 0;
}
sei();
counter++;
// End of Fourier Transform code - output is stored in fht_oct_out[i].
// i=0-7 frequency (octave) bins (don't use 0 or 1), fht_oct_out[1]= amplitude of frequency for bin 1
// for loop a) removes background noise average and takes absolute value b) low / high pass filter as still very noisy
// c) maps amplitude of octave to a colour between blue and red d) sets pixel colour to amplitude of each frequency (octave)
for (int i = 1; i < 8; i++) { // goes through each octave. skip the first 1, which is not useful
int j;
j = (fht_oct_out[i] - noise[i]); // take the pink noise average level out, take the asbolute value to avoid negative numbers
if (j < 10) {
j = 0;
}
j = j * noise_fact_adj[i];
if (j < 10) {
j = 0;
}
else {
j = j * noise_fact_adj[i];
if (j > 180) {
if (i >= 7) {
beat += 2;
}
else {
beat += 1;
}
}
j = j / 30;
j = j * 30; // (force it to more discrete values)
}
prev_j[i] = j;
// Serial.print(j);
// Serial.print(" ");
// this fills in 11 LED's with interpolated values between each of the 8 OCT values
if (i >= 2) {
led_index = 2 * i - 3;
prev_oct_j = (j + prev_j[i - 1]) / 2;
saturation = constrain(j + 50, 0, 255); //-----------50 was 30
saturation_prev = constrain(prev_oct_j + 50, 0, 255);
brightness = constrain(j, 0, 255);
brightness_prev = constrain(prev_oct_j, 0, 255);
if (brightness == 255) {
saturation = 50;
brightness = 200;
}
if (brightness_prev == 255) {
saturation_prev = 50;
brightness_prev = 200;
}
for (uint8_t y = 0; y < kMatrixHeight; y++) {
leds[XY(led_index - 1, y)] = CHSV(j + y * 30, saturation, brightness);
if (i > 2) {
prev_oct_j = (j + prev_j[i - 1]) / 2;
leds[ XY(led_index - 2, y)] = CHSV(prev_oct_j + y * 30, saturation_prev, brightness_prev);
}
}
}
}
if (beat >= 7) {
fill_solid(leds, NUM_LEDS, CRGB::Gray);
FastLED.setBrightness(200);
}
else {
if (prev_beat != beat) {
FastLED.setBrightness(40 + beat * beat * 5);
prev_beat = beat;
}
}
FastLED.show();
if (beat) {
counter2 += ((beat + 4) / 2 - 2);
if (counter2 < 0) {
counter2 = 1000;
}
if (beat > 3 && beat < 7) {
FastLED.delay (20);
}
beat = 0;
}
// Serial.println();
}
}
// Param for different pixel layouts
const bool kMatrixSerpentineLayout = false;
// Set 'kMatrixSerpentineLayout' to false if your pixels are
// laid out all running the same way, like this:
// Set 'kMatrixSerpentineLayout' to true if your pixels are
// laid out back-and-forth, like this:
uint16_t XY( uint8_t x, uint8_t y)
{
uint16_t i;
if ( kMatrixSerpentineLayout == false) {
i = (y * kMatrixWidth) + x;
}
if ( kMatrixSerpentineLayout == true) {
if ( y & 0x01) {
// Odd rows run backwards
uint8_t reverseX = (kMatrixWidth - 1) - x;
i = (y * kMatrixWidth) + reverseX;
} else {
// Even rows run forwards
i = (y * kMatrixWidth) + x;
}
}
i = (i + counter2) % NUM_LEDS;
return i;
}
实验场景图
【花雕动手做】有趣好玩的音乐可视化系列小项目(10)---WS2812硬板屏
项目之四:256位全彩闪动音乐频谱灯(8x32位WS2812硬屏)
实验视频剪辑
https://v.youku.com/v_show/id_XNTgyNzE0MTM3Mg==.html?spm=a2hcb.playlsit.page.1
实验场景动态图
【花雕动手做】有趣好玩的音乐可视化系列小项目(10)---WS2812硬板屏
项目之五:快速哈特利变换FHT音乐反应灯板(8X8位WS2812硬屏)
实验开源代码
/*
【花雕动手做】有趣好玩的音乐可视化系列小项目(10)---WS2812硬板屏
项目之五:快速哈特利变换FHT音乐反应灯板(8X8位WS2812硬屏)
*/
#define qsubd(x, b) ((x>b)?wavebright:0) // A digital unsigned subtraction macro. if result <0, then => 0. Otherwise, take on fixed value.
#define qsuba(x, b) ((x>b)?x-b:0) // Unsigned subtraction macro. if result <0, then => 0.
#define wavebright 128 // qsubd result will be this value if subtraction is >0.
#include "FastLED.h" // FastLED library. Preferably the latest copy of FastLED 2.1.
#if FASTLED_VERSION < 3001000
#error "Requires FastLED 3.1 or later; check github for latest code."
#endif
// Fixed definitions cannot change on the fly.
#define LED_DT 6 // Data pin to connect to the strip.
//#define LED_CK 11 // Clock pin for APA102 or WS2801
#define COLOR_ORDER GRB // It's GRB for WS2812
#define LED_TYPE WS2812B // What kind of strip are you using (APA102, WS2801 or WS2812B)
#define NUM_LEDS 64 // Number of LED's.
// Initialize changeable global variables.
uint8_t max_bright = 255; // Overall brightness definition. It can be changed on the fly.
struct CRGB leds[NUM_LEDS]; // Initialize our LED array.
#define LOG_OUT 1
#define FHT_N 256 // Set to 256 point fht.
#define inputPin A0
//#define potPin A4
#include <FHT.h> // FHT library
uint8_t hueinc = 0; // A hue increment value to make it rotate a bit.
uint8_t micmult = 25;
uint8_t fadetime = 900;
uint8_t noiseval = 25; // Increase this to reduce sensitivity. 30 seems best for quiet
void setup() {
analogReference(EXTERNAL); // Connect 3.3V to AREF pin for any microphones using 3.3V
Serial.begin(9600); // use the serial port
LEDS.addLeds<LED_TYPE, LED_DT, COLOR_ORDER>(leds, NUM_LEDS);
// LEDS.addLeds<LED_TYPE, LED_DT, LED_CK, COLOR_ORDER>(leds, NUM_LEDS);
FastLED.setBrightness(max_bright);
set_max_power_in_volts_and_milliamps(5, 300); // FastLED Power management set at 5V, 500mA.
}
void loop() {
// noiseval = map(analogRead(potPin), 0, 1023, 16, 48); // Adjust sensitivity of cutoff.
EVERY_N_MILLISECONDS(13) {
fhtsound();
}
show_at_max_brightness_for_power();
Serial.println(LEDS.getFPS(), DEC); // Display frames per second on the serial monitor.
Serial.println(" "); // Display frames per second on the serial monitor.
Serial.println(analogRead(inputPin)); // print as an ASCII-encoded decimal */
}
void fhtsound() {
// hueinc++; // A cute little hue incrementer.
GetFHT(); // Let's take FHT_N samples and crunch 'em.
for (int i = 0; i < NUM_LEDS; i++) { // Run through the LED array.
int tmp = qsuba(fht_log_out[2 * i + 2], noiseval); // Get the sample and subtract the 'quiet' normalized values, but don't go < 0.
if (tmp > (leds[i].r + leds[i].g + leds[i].b) / 2) // Refresh an LED only when the intensity is low
leds[i] = CHSV((i * 4) + tmp * micmult, 255, tmp * micmult); // Note how we really cranked up the tmp value to get BRIGHT LED's. Also increment the hue for fun.
leds[i].nscale8(fadetime); // Let's fade the whole thing over time as well.
}
} // fhtsound()
void GetFHT() {
cli();
for (int i = 0 ; i < FHT_N ; i++) fht_input[i] = analogRead(inputPin);
sei();
fht_window(); // Window the data for better frequency response.
fht_reorder(); // Reorder the data before doing the fht.
fht_run(); // Process the data in the fht.
fht_mag_log();
} // GetFHT()
【花雕动手做】有趣好玩的音乐可视化系列小项目(10)---WS2812硬板屏
项目之五:快速哈特利变换FHT音乐反应灯板(8X8位WS2812硬屏)
实验视频剪辑
https://v.youku.com/v_show/id_XNTgwODY2NzkzMg==.html?spm=a2hcb.playlsit.page.1
实验场景动态图
【花雕动手做】有趣好玩的音乐可视化系列小项目(10)---WS2812硬板屏
项目之六:快速哈特利变换FHT音乐反应灯板(8X32位WS2812硬屏)
实验开源代码
/*
【花雕动手做】有趣好玩的音乐可视化系列小项目(10)---WS2812硬板屏
项目之六:快速哈特利变换FHT音乐反应灯板(8X32位 WS2812硬屏)
*/
#define qsubd(x, b) ((x>b)?wavebright:0) // A digital unsigned subtraction macro. if result <0, then => 0. Otherwise, take on fixed value.
#define qsuba(x, b) ((x>b)?x-b:0) // Unsigned subtraction macro. if result <0, then => 0.
#define wavebright 128 // qsubd result will be this value if subtraction is >0.
#include "FastLED.h" // FastLED library. Preferably the latest copy of FastLED 2.1.
#if FASTLED_VERSION < 3001000
#error "Requires FastLED 3.1 or later; check github for latest code."
#endif
// Fixed definitions cannot change on the fly.
#define LED_DT 6 // Data pin to connect to the strip.
//#define LED_CK 11 // Clock pin for APA102 or WS2801
#define COLOR_ORDER GRB // It's GRB for WS2812
#define LED_TYPE WS2812B // What kind of strip are you using (APA102, WS2801 or WS2812B)
#define NUM_LEDS 256 // Number of LED's.
// Initialize changeable global variables.
uint8_t max_bright = 255; // Overall brightness definition. It can be changed on the fly.
struct CRGB leds[NUM_LEDS]; // Initialize our LED array.
#define LOG_OUT 1
#define FHT_N 256 // Set to 256 point fht.
#define inputPin A0
//#define potPin A4
#include <FHT.h> // FHT library
uint8_t hueinc = 0; // A hue increment value to make it rotate a bit.
uint8_t micmult = 25;
uint8_t fadetime = 900;
uint8_t noiseval = 25; // Increase this to reduce sensitivity. 30 seems best for quiet
void setup() {
analogReference(EXTERNAL); // Connect 3.3V to AREF pin for any microphones using 3.3V
Serial.begin(9600); // use the serial port
FastLED.setBrightness (22);
LEDS.addLeds<LED_TYPE, LED_DT, COLOR_ORDER>(leds, NUM_LEDS);
// LEDS.addLeds<LED_TYPE, LED_DT, LED_CK, COLOR_ORDER>(leds, NUM_LEDS);
FastLED.setBrightness(max_bright);
set_max_power_in_volts_and_milliamps(5, 300); // FastLED Power management set at 5V, 500mA.
}
void loop() {
// noiseval = map(analogRead(potPin), 0, 1023, 16, 48); // Adjust sensitivity of cutoff.
EVERY_N_MILLISECONDS(13) {
fhtsound();
}
show_at_max_brightness_for_power();
Serial.println(LEDS.getFPS(), DEC); // Display frames per second on the serial monitor.
Serial.println(" "); // Display frames per second on the serial monitor.
Serial.println(analogRead(inputPin)); // print as an ASCII-encoded decimal */
}
void fhtsound() {
// hueinc++; // A cute little hue incrementer.
GetFHT(); // Let's take FHT_N samples and crunch 'em.
for (int i = 0; i < NUM_LEDS; i++) { // Run through the LED array.
int tmp = qsuba(fht_log_out[2 * i + 2], noiseval); // Get the sample and subtract the 'quiet' normalized values, but don't go < 0.
if (tmp > (leds[i].r + leds[i].g + leds[i].b) / 2) // Refresh an LED only when the intensity is low
leds[i] = CHSV((i * 4) + tmp * micmult, 255, tmp * micmult); // Note how we really cranked up the tmp value to get BRIGHT LED's. Also increment the hue for fun.
leds[i].nscale8(fadetime); // Let's fade the whole thing over time as well.
}
} // fhtsound()
void GetFHT() {
cli();
for (int i = 0 ; i < FHT_N ; i++) fht_input[i] = analogRead(inputPin);
sei();
fht_window(); // Window the data for better frequency response.
fht_reorder(); // Reorder the data before doing the fht.
fht_run(); // Process the data in the fht.
fht_mag_log();
} // GetFHT()
【花雕动手做】有趣好玩的音乐可视化系列小项目(10)---WS2812硬板屏
项目之六:快速哈特利变换FHT音乐反应灯板(8X32位WS2812硬屏)
实验视频剪辑
https://v.youku.com/v_show/id_XNTgyNzY0NTc5Mg==.html?spm=a2hcb.playlsit.page.1
实验场景动态图
【花雕动手做】有趣好玩的音乐可视化系列小项目(10)---WS2812硬板屏
项目之七:基于虚拟轮生成颜色的音乐可视化(8X32位 WS2812硬屏)
/*
【花雕动手做】有趣好玩的音乐可视化系列小项目(10)---WS2812硬板屏
项目之七:基于虚拟轮生成颜色的音乐可视化(8X32位 WS2812硬屏)
*/
#include <FastLED.h>
// LED LIGHTING SETUP
#define LED_PIN 6
#define NUM_LEDS 480
#define BRIGHTNESS 30
#define LED_TYPE WS2811
#define COLOR_ORDER GRB
CRGB leds[NUM_LEDS];
#define UPDATES_PER_SECOND 100
// AUDIO INPUT SETUP
int audio = A0;
// STANDARD VISUALIZER VARIABLES
int loop_max = 0;
int k = 255; // COLOR WHEEL POSITION
int decay = 0; // HOW MANY MS BEFORE ONE LIGHT DECAY
int decay_check = 0;
long pre_react = 0; // NEW SPIKE CONVERSION
long react = 0; // NUMBER OF LEDs BEING LIT
long post_react = 0; // OLD SPIKE CONVERSION
// RAINBOW WAVE SETTINGS
int wheel_speed = 4;
void setup()
{
// LED LIGHTING SETUP
delay( 3000 ); // power-up safety delay
FastLED.addLeds<LED_TYPE, LED_PIN, COLOR_ORDER>(leds, NUM_LEDS).setCorrection( TypicalLEDStrip );
FastLED.setBrightness( BRIGHTNESS );
// CLEAR LEDS
for (int i = 0; i < NUM_LEDS; i++)
leds[i] = CRGB(0, 0, 0);
FastLED.show();
// SERIAL AND INPUT SETUP
Serial.begin(115200);
pinMode(audio, INPUT);
Serial.println("\nListening...");
}
CRGB Scroll(int pos) {
CRGB color (0,0,0);
if(pos < 85) {
color.g = 0;
color.r = ((float)pos / 85.0f) * 255.0f;
color.b = 255 - color.r;
} else if(pos < 170) {
color.g = ((float)(pos - 85) / 85.0f) * 255.0f;
color.r = 255 - color.g;
color.b = 0;
} else if(pos < 256) {
color.b = ((float)(pos - 170) / 85.0f) * 255.0f;
color.g = 255 - color.b;
color.r = 1;
}
return color;
}
void rainbow(){
for(int i = NUM_LEDS - 1; i >= 0; i--) {
if (i < react)
leds[i] = Scroll((i * 256 / 50 + k) % 256);
else
leds[i] = CRGB(0, 0, 0);
}
FastLED.show();
}
void loop()
{
int audio_input = analogRead(audio); // ADD x2 HERE FOR MORE SENSITIVITY
if (audio_input > 0)
{
pre_react = ((long)NUM_LEDS * (long)audio_input) / 1023L; // TRANSLATE AUDIO LEVEL TO NUMBER OF LEDs
if (pre_react > react) // ONLY ADJUST LEVEL OF LED IF LEVEL HIGHER THAN CURRENT LEVEL
react = pre_react;
Serial.print(audio_input);
Serial.print(" -> ");
Serial.println(pre_react);
}
rainbow(); // APPLY COLOR
k = k - wheel_speed; // SPEED OF COLOR WHEEL
if (k < 0) // RESET COLOR WHEEL
k = 255;
// REMOVE LEDs
decay_check++;
if (decay_check > decay)
{
decay_check = 0;
if (react > 0)
react--;
}
//delay(1);
}
实验场景图 动态图
【花雕动手做】有趣好玩的音乐可视化系列小项目(10)---WS2812硬板屏
项目之八:通过快速傅里叶变换在ws2812b8*8灯板上显示频谱
/*
【花雕动手做】有趣好玩的音乐可视化系列小项目(10)---WS2812硬板屏
项目之八:通过快速傅里叶变换在ws2812b8*8灯板上显示频谱
*/
#include "arduinoFFT.h"
#include <FastLED.h>
#define NUM_LEDS 64
#define LED_TYPE WS2812
#define COLOR_ORDER GRB
arduinoFFT FFT = arduinoFFT();
CRGB leds[NUM_LEDS];
#define CHANNEL A0
#define DATA_PIN 6
const uint8_t max_bright = 2;
const uint16_t samples = NUM_LEDS / 4;
const byte halfsamples = samples / 2;
uint8_t gHue;
int value;
double vReal[samples];
double vImag[samples];
char toData[halfsamples];
int pointJump[halfsamples];
int uJump[halfsamples];
int dJump[halfsamples];
int uValue;
int dValue;
int tValue;
int toDown = 0;
uint8_t toDownSpeed = 3;
int pointDown = 0;
uint8_t pointDownSpeed = 9;
void setup(){
delay(100);
Serial.println("Ready");
FastLED.addLeds<LED_TYPE, DATA_PIN, COLOR_ORDER>(leds, NUM_LEDS).setCorrection(TypicalLEDStrip);
FastLED.setBrightness(max_bright);
}
void loop(){
FastLED.clear();
EVERY_N_MILLISECONDS(10) {
gHue += 10;
}
for (int i = 0; i < samples; i++)
{
value = analogRead(CHANNEL);
vReal[i] = value;
vImag[i] = 0.0;
}
FFT.Windowing(vReal, samples, FFT_WIN_TYP_HAMMING, FFT_FORWARD);
FFT.Compute(vReal, vImag, samples, FFT_FORWARD);
FFT.ComplexToMagnitude(vReal, vImag, samples);
for (int i = 0; i < halfsamples; i++)
{
toData[i] = vReal[i + halfsamples / 2];
toData[i] = constrain(toData[i], 0, 100);
toData[i] = map(toData[i], 0, 100, 1, 7);
}
for (int i = 0; i < halfsamples; i++)
{
uValue = toData[i];
uJump[i]++;
if (uValue > uJump[i])
{
uValue = uJump[i];
}
else
{
uJump[i] = uValue;
}
dValue = uValue;
toDown++;
if (toDown % toDownSpeed == 0)
{
dJump[i]--;
toDown = 0;
}
if (dValue > pointJump[i])
{
dJump[i] = dValue;
}
else
{
dValue = dJump[i];
}
tValue = uValue;
pointDown++;
if (pointDown % pointDownSpeed == 0)
{
pointJump[i]--;
pointDown = 0;
}
if (tValue > pointJump[i])
{
pointJump[i] = tValue;
}
else
{
tValue = pointJump[i];
}
fill_rainbow(leds + 8 * i, uValue, gHue, 30);
fill_rainbow(leds + 8 * i, dValue, gHue, 30);
fill_solid(leds + 8 * i + tValue, 1, CRGB::White);
}
FastLED.show();
delay(10);
}
实验场景图 动态图
【花雕动手做】有趣好玩的音乐可视化系列小项目(10)---WS2812硬板屏
项目之九:FastLED多彩音乐节奏屏灯
/*
【花雕动手做】有趣好玩的音乐可视化系列小项目(10)---WS2812硬板屏
项目之九:FastLED多彩音乐节奏屏灯
*/
#include<FastLED.h>
#include<MegunoLink.h>
#include<Filter.h>
// define necessary parameters
#define N_PIXELS 64
#define MIC_PIN A0
#define LED_PIN 6
// the following parameters can be tweaked according to your audio levels
#define NOISE 240
#define TOP (N_PIXELS+2) // allow the max level to be slightly off scale
#define LED_TYPE WS2811
#define BRIGHTNESS 34 // a little dim for recording purposes
#define COLOR_ORDER GRB
// declare the LED array
CRGB leds[N_PIXELS];
// define the variables needed for the audio levels
int lvl = 0, minLvl = 0, maxLvl = 300; // tweak the min and max as needed
// instantiate the filter class for smoothing the raw audio signal
ExponentialFilter<long> ADCFilter(5, 0);
void setup() {
// put your setup code here, to run once:
// Serial.begin(115200);
// initialize the LED object
FastLED.addLeds<LED_TYPE, LED_PIN, COLOR_ORDER>(leds, N_PIXELS).setCorrection(TypicalLEDStrip);
FastLED.setBrightness(BRIGHTNESS);
}
void loop() {
// put your main code here, to run repeatedly:
// read the audio signal and filter it
int n, height;
n = analogRead(MIC_PIN);
// remove the MX9614 bias of 1.25VDC
n = abs(1023 - n);
// hard limit noise/hum
n = (n <= NOISE) ? 0 : abs(n - NOISE);
// apply the exponential filter to smooth the raw signal
ADCFilter.Filter(n);
lvl = ADCFilter.Current();
// // plot the raw versus filtered signals
//Serial.print(n);
//Serial.print(" ");
//Serial.println(lvl);
// calculate the number of pixels as a percentage of the range
// TO-DO: can be done dynamically by using a running average of min/max audio levels
height = TOP * (lvl - minLvl) / (long)(maxLvl - minLvl);
if (height < 0L) height = 0;
else if (height > TOP) height = TOP;
// turn the LEDs corresponding to the level on/off
for (uint8_t i = 0; i < N_PIXELS; i++) {
// turn off LEDs above the current level
if (i >= height) leds[i] = CRGB(0, 0, 0);
// otherwise, turn them on!
else leds[i] = Wheel( map( i, 0, N_PIXELS - 1, 30, 150 ) );
}
FastLED.show();
}
CRGB Wheel(byte WheelPos) {
// return a color value based on an input value between 0 and 255
if (WheelPos < 85)
return CRGB(WheelPos * 3, 255 - WheelPos * 3, 0);
else if (WheelPos < 170) {
WheelPos -= 85;
return CRGB(255 - WheelPos * 3, 0, WheelPos * 3);
} else {
WheelPos -= 170;
return CRGB(0, WheelPos * 3, 255 - WheelPos * 3);
}
}
实验场景图 动态图
【花雕动手做】有趣好玩的音乐可视化系列小项目(10)---WS2812硬板屏
项目之十:Arduino 和 FastLED多彩音乐灯
/*
【花雕动手做】有趣好玩的音乐可视化系列小项目(10)---WS2812硬板屏
项目之十:Arduino 和 FastLED多彩音乐灯
*/
#include <FastLED.h>
#define SAMPLEPERIODUS 200
#define MIC_PIN A0
#define LED_DT 6
#define COLOR_ORDER GRB
#define LED_TYPE WS2812
#define NUM_LEDS 256
uint8_t max_bright = 33;
struct CRGB leds[NUM_LEDS];
CRGBPalette16 currentPalette = RainbowColors_p;
CRGBPalette16 targetPalette;
void setup() {
pinMode(LED_BUILTIN, OUTPUT);
LEDS.addLeds<LED_TYPE, LED_DT, COLOR_ORDER>(leds, NUM_LEDS);
FastLED.setBrightness(max_bright);
}
float bassFilter(float sample) {
static float xv[3] = {0, 0, 0}, yv[3] = {0, 0, 0};
xv[0] = xv[1]; xv[1] = xv[2];
xv[2] = sample / 9.1f;
yv[0] = yv[1]; yv[1] = yv[2];
yv[2] = (xv[2] - xv[0]) + (-0.7960060012f * yv[0]) + (1.7903124146f * yv[1]);
return yv[2];
}
float envelopeFilter(float sample) {
static float xv[2] = {0, 0}, yv[2] = {0, 0};
xv[0] = xv[1];
xv[1] = sample / 160.f;
yv[0] = yv[1];
yv[1] = (xv[0] + xv[1]) + (0.9875119299f * yv[0]);
return yv[1];
}
float beatFilter(float sample) {
static float xv[3] = {0, 0, 0}, yv[3] = {0, 0, 0};
xv[0] = xv[1]; xv[1] = xv[2];
xv[2] = sample / 7.015f;
yv[0] = yv[1]; yv[1] = yv[2];
yv[2] = (xv[2] - xv[0]) + (-0.7169861741f * yv[0]) + (1.4453653501f * yv[1]);
return yv[2];
}
void loop() {
unsigned long time = micros();
float sample, value, envelope, beat, thresh, micLev;
for (uint8_t i = 0; ; ++i) {
sample = (float)analogRead(MIC_PIN);
micLev = ((micLev * 67) + sample) / 68;
sample -= micLev;
value = bassFilter(sample);
value = abs(value);
envelope = envelopeFilter(value);
if (i == 200) {
beat = beatFilter(envelope);
thresh = 0.02f * 75.;
if (beat > thresh) {
digitalWrite(LED_BUILTIN, LOW);
int strt = random8(NUM_LEDS / 2);
int ende = strt + random8(NUM_LEDS / 2);
for (int i = strt; i < ende; i++) {
uint8_t index = inoise8(i * 30, millis() + i * 30);
leds[i] = ColorFromPalette(currentPalette, index, 255, LINEARBLEND);
}
} else {
digitalWrite(LED_BUILTIN, HIGH);
}
i = 0;
}
EVERY_N_SECONDS(5) {
uint8_t baseC = random8();
targetPalette = CRGBPalette16(CHSV(baseC + random8(32), 255, random8(128, 255)),
CHSV(baseC + random8(64), 255, random8(128, 255)),
CHSV(baseC + random8(64), 192, random8(128, 255)),
CHSV(baseC + random8(), 255, random8(128, 255)));
}
EVERY_N_MILLISECONDS(50) {
uint8_t maxChanges = 24;
nblendPaletteTowardPalette(currentPalette, targetPalette, maxChanges);
}
EVERY_N_MILLIS(50) {
fadeToBlackBy(leds, NUM_LEDS, 64);
FastLED.show();
}
for (unsigned long up = time + SAMPLEPERIODUS; time > 20 && time < up; time = micros()) { }
} // for i
} // loop()
实验的视频记录
优酷:
B站:https://www.bilibili.com/video/BV1L14y157PU/?vd_source=98c6b1fc23b2787403d97f8d3cc0b7e5
【Arduino】168种传感器模块系列实验(资料代码+仿真编程+图形编程)
实验一百七十七:Wemos D1 R32 ESP32开发板
项目之四十六:基于虚拟轮生成颜色的256位音乐可视化
/*
【Arduino】168种传感器模块系列实验(资料代码+仿真编程+图形编程)
实验一百七十七:Wemos D1 R32 ESP32开发板
项目之四十六:基于虚拟轮生成颜色的256位音乐可视化
*/
#include <FastLED.h>
// LED LIGHTING SETUP
#define LED_PIN 23
#define NUM_LEDS 256
#define BRIGHTNESS 30
#define LED_TYPE WS2811
#define COLOR_ORDER GRB
CRGB leds[NUM_LEDS];
#define UPDATES_PER_SECOND 100
// AUDIO INPUT SETUP
int audio = 38;
// STANDARD VISUALIZER VARIABLES
int loop_max = 0;
int k = 255; // COLOR WHEEL POSITION
int decay = 0; // HOW MANY MS BEFORE ONE LIGHT DECAY
int decay_check = 0;
long pre_react = 0; // NEW SPIKE CONVERSION
long react = 0; // NUMBER OF LEDs BEING LIT
long post_react = 0; // OLD SPIKE CONVERSION
// RAINBOW WAVE SETTINGS
int wheel_speed = 4;
void setup()
{
// LED LIGHTING SETUP
delay( 3000 ); // power-up safety delay
FastLED.addLeds<LED_TYPE, LED_PIN, COLOR_ORDER>(leds, NUM_LEDS).setCorrection( TypicalLEDStrip );
FastLED.setBrightness( BRIGHTNESS );
// CLEAR LEDS
for (int i = 0; i < NUM_LEDS; i++)
leds[i] = CRGB(0, 0, 0);
FastLED.show();
// SERIAL AND INPUT SETUP
Serial.begin(115200);
pinMode(audio, INPUT);
Serial.println("\nListening...");
}
CRGB Scroll(int pos) {
CRGB color (0,0,0);
if(pos < 85) {
color.g = 0;
color.r = ((float)pos / 85.0f) * 255.0f;
color.b = 255 - color.r;
} else if(pos < 170) {
color.g = ((float)(pos - 85) / 85.0f) * 255.0f;
color.r = 255 - color.g;
color.b = 0;
} else if(pos < 256) {
color.b = ((float)(pos - 170) / 85.0f) * 255.0f;
color.g = 255 - color.b;
color.r = 1;
}
return color;
}
void rainbow(){
for(int i = NUM_LEDS - 1; i >= 0; i--) {
if (i < react)
leds[i] = Scroll((i * 256 / 50 + k) % 256);
else
leds[i] = CRGB(0, 0, 0);
}
FastLED.show();
}
void loop(){
int audio_input = analogRead(audio)*5.5; // 在此处调整,以获得更多敏感性
if (audio_input > 0)
{
pre_react = ((long)NUM_LEDS * (long)audio_input) / 1023L; // TRANSLATE AUDIO LEVEL TO NUMBER OF LEDs
if (pre_react > react) // ONLY ADJUST LEVEL OF LED IF LEVEL HIGHER THAN CURRENT LEVEL
react = pre_react;
Serial.print(audio_input);
Serial.print(" -> ");
Serial.println(pre_react);
}
rainbow(); // APPLY COLOR
k = k - wheel_speed; // SPEED OF COLOR WHEEL
if (k < 0) // RESET COLOR WHEEL
k = 255;
// REMOVE LEDs
decay_check++;
if (decay_check > decay)
{
decay_check = 0;
if (react > 0)
react--;
}
delay(1);
}
实验场景图 动态图
实验的视频记录
优酷:https://v.youku.com/v_show/id_XNTkyMTAwNDQwOA==.html?spm=a2hcb.playlsit.page.1
B站:https://www.bilibili.com/video/BV1gP4y117Xx/?vd_source=98c6b1fc23b2787403d97f8d3cc0b7e5
【Arduino】168种传感器模块系列实验(资料代码+仿真编程+图形编程)
实验一百七十七:Wemos D1 R32 ESP32开发板
项目之四十七:快速傅里叶变换256位频谱仪
/*
【Arduino】168种传感器模块系列实验(资料代码+仿真编程+图形编程)
实验一百七十七:Wemos D1 R32 ESP32开发板
项目之四十七:快速傅里叶变换256位频谱仪
*/
#include "arduinoFFT.h"
#include <FastLED.h>
#define NUM_LEDS 256
#define LED_TYPE WS2812
#define COLOR_ORDER GRB
arduinoFFT FFT = arduinoFFT();
CRGB leds[NUM_LEDS];
#define CHANNEL 39
#define DATA_PIN 23
const uint8_t max_bright = 2;
const uint16_t samples = NUM_LEDS / 4;
const byte halfsamples = samples / 2;
uint8_t gHue;
int value;
double vReal[samples];
double vImag[samples];
char toData[halfsamples];
int pointJump[halfsamples];
int uJump[halfsamples];
int dJump[halfsamples];
int uValue;
int dValue;
int tValue;
int toDown = 0;
uint8_t toDownSpeed = 3;
int pointDown = 0;
uint8_t pointDownSpeed = 9;
void setup(){
delay(100);
Serial.println("Ready");
FastLED.addLeds<LED_TYPE, DATA_PIN, COLOR_ORDER>(leds, NUM_LEDS).setCorrection(TypicalLEDStrip);
FastLED.setBrightness(max_bright);
}
void loop(){
FastLED.clear();
EVERY_N_MILLISECONDS(10) {
gHue += 10;
}
for (int i = 0; i < samples; i++)
{
value = analogRead(CHANNEL);
vReal[i] = value;
vImag[i] = 0.0;
}
FFT.Windowing(vReal, samples, FFT_WIN_TYP_HAMMING, FFT_FORWARD);
FFT.Compute(vReal, vImag, samples, FFT_FORWARD);
FFT.ComplexToMagnitude(vReal, vImag, samples);
for (int i = 0; i < halfsamples; i++)
{
toData[i] = vReal[i + halfsamples / 2];
toData[i] = constrain(toData[i], 0, 100);
toData[i] = map(toData[i], 0, 100, 1, 7);
}
for (int i = 0; i < halfsamples; i++)
{
uValue = toData[i];
uJump[i]++;
if (uValue > uJump[i])
{
uValue = uJump[i];
}
else
{
uJump[i] = uValue;
}
dValue = uValue;
toDown++;
if (toDown % toDownSpeed == 0)
{
dJump[i]--;
toDown = 0;
}
if (dValue > pointJump[i])
{
dJump[i] = dValue;
}
else
{
dValue = dJump[i];
}
tValue = uValue;
pointDown++;
if (pointDown % pointDownSpeed == 0)
{
pointJump[i]--;
pointDown = 0;
}
if (tValue > pointJump[i])
{
pointJump[i] = tValue;
}
else
{
tValue = pointJump[i];
}
fill_rainbow(leds + 8 * i, uValue, gHue, 30);
fill_rainbow(leds + 8 * i, dValue, gHue, 30);
fill_solid(leds + 8 * i + tValue, 1, CRGB::White);
}
FastLED.show();
delay(2);
}
实验场景图
实验的视频记录
优酷:https://v.youku.com/v_show/id_XNTkxOTQxODA2OA==.html?spm=a2hcb.playlsit.page.3
B站:https://www.bilibili.com/video/BV1ye4y1s7n1/?vd_source=98c6b1fc23b2787403d97f8d3cc0b7e5
实验场景图 动态图
实验的视频记录
优酷:https://v.youku.com/v_show/id_XNTkxOTQxODEzNg==.html?spm=a2hcb.playlsit.page.1
B站:https://www.bilibili.com/video/BV1hg411q7yo/?vd_source=98c6b1fc23b2787403d97f8d3cc0b7e5
翟2022.01.11
求 FHT.h 库文件 谢谢谢谢谢 2653458124@qq.com
驴友花雕2022.07.14
不好意思,刚看到,还需要吗?