#include <Adafruit_NeoPixel.h>
#include <vector>
const int LED_PIN = 16;
const int ADC_PIN = 34; // 设置ADC引脚
const int SAMPLE_RATE = 16000; // 设置采样率
const int SAMPLE_SIZE = 64; // 设置采样位数
// NEO_GRB + NEO_KHZ800
// 这是指定 LED 带使用的颜色顺序和通信速率。
// 这里使用了 GRB 颜色顺序(即绿色、红色、蓝色)
// 以及 800kHz 的通信速率
class LedScreenDriver;
enum DrawCallType{
Null, PreFrame, PreX, PreY, PreXY
};
struct BaseArgs {
BaseArgs(int x, int y)
:x(x), y(y){}
int x, y;
};
typedef void (*DrawCallBack)(LedScreenDriver*, BaseArgs&);
struct DrawCallFunc
{
DrawCallFunc(DrawCallType type, DrawCallBack func)
:type(type), ptr(func)
{}
DrawCallFunc()
:type(DrawCallType::PreXY), ptr(nullptr)
{}
inline void operator()(LedScreenDriver* driver, BaseArgs& args){
ptr(driver, args);
}
DrawCallType type;
DrawCallBack ptr;
};
class LedScreenDriver {
private:
bool bFlipY;
bool bShortYMode;
int numPixels;
int selPixel;
int screenWidth;
int screenHeight;
Adafruit_NeoPixel strip;
public:
DrawCallFunc drawCalls[8];
public:
LedScreenDriver(int dataPin, int screenWidth, int screenHeight);
void Init();
void Clear(int red, int green, int blue);
void SetBrightness(int brightness);
void SetColor(int red, int green, int blue);
void SelectPixel(int x, int y);
void FlipY(bool bEnable);
void ShortYMode(bool bEnable);
void Clear();
void Show();
int GetNumPixels();
int GetScreenWidth();
int GetScreenHeight();
};
struct AudioArgs : public BaseArgs
{
AudioArgs(int x, int y, int height, int peak)
:BaseArgs(x, y), height(height), peak(peak){
}
int height;
int peak;
};
LedScreenDriver::LedScreenDriver(int dataPin, int screenWidth, int screenHeight)
: strip(screenWidth * screenHeight, dataPin, NEO_GRB + NEO_KHZ800)
, numPixels(screenWidth * screenHeight)
, bFlipY(false)
, bShortYMode(false) {
this->screenWidth = screenWidth;
this->screenHeight = screenHeight;
}
void LedScreenDriver::Init() {
strip.begin();
strip.show(); // Initialize all pixels to 'off'
}
void LedScreenDriver::Clear(int red, int green, int blue) {
for (int i = 0; i < numPixels; i++) {
strip.setPixelColor(i, red, green, blue);
}
}
void LedScreenDriver::SetBrightness(int brightness) {
strip.setBrightness(brightness);
}
void LedScreenDriver::SetColor(int red, int green, int blue) {
strip.setPixelColor(selPixel, red, green, blue);
}
void LedScreenDriver::SelectPixel(int x, int y) {
// bFlipY:整体垂直取反
// bShortYMode:垂直取反偶数列
const bool& _bFlipY = bFlipY ^ (bShortYMode && x%2!=0);
selPixel = x * screenHeight + (_bFlipY ? (screenHeight - 1 - y) : y);
}
void LedScreenDriver::FlipY(bool bEnable) {
bFlipY = bEnable;
}
void LedScreenDriver::ShortYMode(bool bEnable) {
bShortYMode = bEnable;
}
void LedScreenDriver::Clear() {
strip.clear();
}
void LedScreenDriver::Show() {
strip.show();
}
int LedScreenDriver::GetNumPixels() {
return numPixels;
}
int LedScreenDriver::GetScreenWidth() {
return screenWidth;
}
int LedScreenDriver::GetScreenHeight() {
return screenHeight;
}
struct DefaultDrawer{
static void DrawBackground(LedScreenDriver* driver, BaseArgs& args){
// AudioArgs& in = *(AudioArgs*)&args;
// // 空白处
// for (int y = in.height + (in.height != 0); y < driver->GetScreenHeight(); ++y) {
// driver->SelectPixel(in.x, y);
// driver->SetColor(30, 0, 0); // Green color for the column
// }
}
static void DrawForeground(LedScreenDriver* driver, BaseArgs& args){
// AudioArgs& in = *(AudioArgs*)&args;
// // 显示处
// for (int y = 0; y < in.height; ++y) {
// driver->SelectPixel(in.x, y);
// driver->SetColor(0, 255, 150); // Green color for the column
// }
}
static void DrawOverlayer(LedScreenDriver* driver, BaseArgs& args){
AudioArgs& in = *(AudioArgs*)&args;
// 顶点
// if (in.peak > 0)
{
const int& y = std::min(in.peak, driver->GetScreenHeight()-1);
driver->SelectPixel(in.x, min(in.x, driver->GetScreenHeight()-1));
driver->SetColor(255, 0, 0); // Red color for the peak
}
}
};
class AudioSpectrumDriver : public LedScreenDriver {
public:
AudioSpectrumDriver(int dataPin, int screenWidth, int screenHeight);
void Clear();
// 使用提供的列高度更新显示
void InputData(int x, int height);
private:
// 绘制单个列的辅助函数
void drawColumn(int x, int height, int peak);
// 更新峰值位置的辅助函数
void updatePeaks();
// 存储每个列的当前峰值位置
std::vector<int> peakPositions;
std::vector<int> heightList;
// 存储每个列自上次峰值更新以来经过的时间
long peakUpdateTimes;
};
AudioSpectrumDriver::AudioSpectrumDriver(int dataPin, int screenWidth, int screenHeight)
: LedScreenDriver(dataPin, screenWidth, screenHeight),
peakPositions(screenWidth, screenHeight),
heightList(screenWidth, 0),
peakUpdateTimes(0)
{
int i = 0;
drawCalls[i++] = DrawCallFunc(DrawCallType::PreXY, &DefaultDrawer::DrawBackground);
drawCalls[i++] = DrawCallFunc(DrawCallType::PreXY, &DefaultDrawer::DrawForeground);
drawCalls[i++] = DrawCallFunc(DrawCallType::PreXY, &DefaultDrawer::DrawOverlayer);
}
void AudioSpectrumDriver::InputData(int x, int height) {
int& peak = peakPositions[x];
if (peak < height)
peak = height ;
// const int ms = 5;
// const int del = (millis() - peakUpdateTimes)/ms;
// if(del>0)
// {
// // for(size_t i = 0; i<heightList.size(); i++ ){
// // heightList[i]-=max(heightList[i], del);
// heightList[x]-=max(heightList[x], del);
// // }
// Serial.print(del);
// Serial.print(" ");
// }
// if (heightList[x] < height)
// heightList[x] = height;
// drawColumn(x, heightList[x], peak);
// return;
drawColumn(x, height, peak);
}
void AudioSpectrumDriver::Clear() {
LedScreenDriver::Clear();
updatePeaks();
}
void AudioSpectrumDriver::drawColumn(int x, int height, int peak) {
AudioArgs args(x, 0, height, peak);
for(int i = 0; i < sizeof(drawCalls)/sizeof(drawCalls[0]); i++){
DrawCallFunc& func = drawCalls[i];
if(func.ptr)
func(this, args);
else
break;
}
}
void AudioSpectrumDriver::updatePeaks() {
const long& currentTime = millis();
if (currentTime - peakUpdateTimes > 33) { // 50 ms delay for peak drop
for (int x = 0; x < peakPositions.size(); ++x)
peakPositions[x] = std::max(0, peakPositions[x] - 1);
peakUpdateTimes = currentTime;
}
}
LedScreenDriver screen(LED_PIN, 1, 144*2);
AudioSpectrumDriver audioScreen(LED_PIN, 16, 8);
// AudioSpectrumDriver audioScreen(LED_PIN, 8, 20);
#define MakeStyle(type) &type::DrawBackground,&type::DrawForeground,&type::DrawOverlayer
void setup() {
// 初始化串口
Serial.begin(115200);
// initialize digital pin LED_BUILTIN as an output.
pinMode(2, OUTPUT);
screen.Init();
audioScreen.Init();
}
#include "driver/adc.h"
int samples[SAMPLE_SIZE];
int frameCount = 0;
void screenTest(){
screen.SetBrightness(2);
// screen.FlipY(frameCount%2);
screen.Clear();
// screen.Show(); // Update the colors on the LED strip
// delay(200); // Wait for half a second
// // Set the color of each pixel
// for(int x = 0; x < screen.GetScreenWidth();x++){
// // for(int y = 0; y < 1;y++){
// screen.SelectPixel(x, abs((x%screen.GetScreenHeight())));
// screen.SetColor(255, 0, 0); // Red
// // }
// }
// Set the color of each pixel
// for(int x = 0; x < screen.GetScreenWidth();x++){
for(int y = 1; y < 144-1;y++){
screen.SelectPixel(0, y);
screen.SetColor(156, 250, 0); // Red
}
// }
screen.Show(); // Update the colors on the LED strip
delay(200); // Wait for half a second
screen.Clear();
screen.SelectPixel(0, 0);
screen.SetColor(200, 0, 0); // Red
screen.SelectPixel(0, 143);
screen.SetColor(200, 0, 0); // Red
screen.Show(); // Update the colors on the LED strip
delay(200); // Wait for half a second
screen.Clear();
for(int y = 1+144; y < 144-1+144;y++){
screen.SelectPixel(0, y);
screen.SetColor(156, 250, 0); // Red
}
screen.Show(); // Update the colors on the LED strip
delay(200); // Wait for half a second
screen.Clear();
screen.SelectPixel(0, 0+144);
screen.SetColor(200, 0, 0); // Red
screen.SelectPixel(0, 143+144);
screen.SetColor(200, 0, 0); // Red
screen.Show(); // Update the colors on the LED strip
delay(200); // Wait for half a second
}
void audioScreenTest(){
float sample = analogRead(ADC_PIN); // 输出读取的电压值
// sample = float(sample - 2048) / 2048.0;
sample/=4096;
sample=sample-(1.25/3.3);
sample*=2;
Serial.println(sample);
const long& time = millis();
auto& screen = audioScreen;
screen.SetBrightness(2);
// screen.ShortYMode(true);
screen.FlipY(true);
screen.Clear();
// 1
// // Set the color of each pixel
// for(int x = 0; x < screen.GetScreenWidth();x++){
// screen.InputData(x, abs(sin(x/4.0+time/300.0))/1.0f*screen.GetScreenHeight());
// }
// 2
// Set the color of each pixel
for(int x = 0; x < screen.GetScreenWidth();x++){
screen.InputData(x, abs(sample/*>0?sample:0*/)*screen.GetScreenHeight());
}
screen.Show();
delay(16); // Wait for half a second
}
unsigned long _time = 0;
void audioScreenTest2(float sample){
auto& screen = audioScreen;
screen.SetBrightness(80);
// screen.ShortYMode(true);
screen.FlipY(true);
screen.Clear();
for(int x = 0; x < screen.GetScreenWidth();x++){
screen.InputData(x, (sample/600.0)*screen.GetScreenHeight());
}
screen.Show();
auto dt = 16 - int(millis() - _time);
if(dt>0)
delay(dt); // Wait for half a second
}
float aduioSample = 0;
void Adc16khz(){
aduioSample = 0;
// 配置ADC
// adc1_config_width(SAMPLE_SIZE);
// adc1_config_channel_atten(ADC1_CHANNEL_6, ADC_ATTEN_DB_11);
// // 进行采样
// for (int i = 0; i < SAMPLE_SIZE; i++) {
// sample = analogRead(34);
// sample = sample - (1.25/3.3)*4096;
// samples[i] = abs(sample);
// delayMicroseconds(1000000/SAMPLE_RATE); // 等待下一个采样点
// }
// // 输出采样结果
// for (int i = 0; i < SAMPLE_SIZE; i++) {
// auto a = float(samples[i]);
// Serial.println(a);
// }
// 进行采样
for (int i = 0; i < SAMPLE_SIZE; i++) {
aduioSample += abs(analogRead(ADC_PIN) - (1.25/3.3)*4096);
delayMicroseconds(1000000/SAMPLE_RATE); // 等待下一个采样点
}
aduioSample = aduioSample/SAMPLE_SIZE;
aduioSample = aduioSample - 60;
aduioSample = (aduioSample>0)?aduioSample:0;
// Serial.println(aduioSample);
}
void loop() {
_time = millis();
// screenTest();
Adc16khz();
auto dt = millis() - _time;
Serial.print(dt);
Serial.print(" ");
audioScreenTest2(aduioSample);
auto dt2 = millis() - _time;
Serial.println(dt2);
digitalWrite(2, frameCount%2); // turn the LED on (HIGH is the voltage level)
frameCount++;
}