13浏览
查看: 13|回复: 2

[项目] 【Arduino 动手做】RGB 32 频段音频频谱可视化器

[复制链接]
该项目无非是对Shajeeb发布的基于MAX72xx的原始项目的WS2812B LED矩阵的改编。

项目
该项目用于使用 Arduino Nano 和 8x32 WS2812B RGB Led 矩阵制作 RGB 32 频段音频(音乐)频谱可视化器。
激发此灵感的原始项目
非常感谢基于MAX72xx LED矩阵的原始项目的作者Shajeeb。我只是修改了 LED 矩阵的先导部分,使其适应 RGB WS2812B Led 矩阵。
原始项目链接:32 波段音频频谱可视化分析仪
WS2812B RGB LED 矩阵
使用基于 5050 SMD 高亮度 LED 的 RGB LED 矩阵,有必要使用外部电源,因为 RGB 矩阵每个 LED 可以吸收超过 10mA 的电流,因此所有 LED 都以最大亮度点亮可以吸收超过 2.5 安培的电流。
出于这个原因,我插入了一个 +5V 串联的二极管,以便在未连接 USB 电缆时能够在独立模式下为 Arduino 供电,并避免 Arduino 成为 RGB 矩阵的电源,从而避免电路板的内部电路过载它无法提供的电流。
在最初的项目中,除了输入二极管之外,为了保护 LED 矩阵输入免受可能的电压峰值的影响,我还在 Arduino 引脚 D6 和数据输入之间添加了一个串联的 390 欧姆电阻,以及一个 1000 μF 12V 电容器以提高 Arduino 电源电压稳定性。
硬件组装
如主照片所示,我使用两个 RCA 音频插座(直接焊接在板上)在 4x6 厘米多孔板上制作了第一个原型,也可以用 3.5 毫米母插孔插座代替。避免嗡嗡声的重要一点是使用屏蔽电缆在源和卡音频输入之间进行连接。另一个技巧是保持 Arduino 和 LED 矩阵之间的连接尽可能短。
代码
最后,所有软件都是基于采样程序的作者通过 FFT 库所做的出色工作和 Shajeeb 的最终实现。
我添加了两个功能:
第一个是 GetLedFromMatrix(...) 将矩阵映射到行和列中,并能够通过行和列坐标对 256 个 LED 中的每一个进行寻址。
第二个是那个 - 我任意地将其称为 SetColumn(... - 它根据音频数字化获得的峰值(值在 0 到 7 之间)和二维数组中的预设颜色打开每列的 LED。您可以根据自己的喜好更改值和颜色,从而获得乐趣。为了简化代码,我使用了一个名为 Wheel() 的 sobroutine(取自 Adafruit 的 Neopixel 库附加的演示),该例程从 0 到 255 之间的值开始返回一个无符号的 32 位长值,然后直接传递给 setPixelColor 函数。在这方面,您可以随意玩,同时牢记 Arduino 的内存限制,尽可能避免使用 32 位变量来存储 RGB 颜色值。
音频均衡
此外,由于我已经使用来自集成在 PC 主板中的声卡的音频运行了测试,为了改善频率响应,我添加了一个包含 32 个值的字节数组,这些值实际上构成了均衡曲线以衰减低音并增强高音。如果不需要,只需将EQ_ON变量设置为false或通过更改eq[32]数组的32个值来更改衰减级别 ,值100使幅度保持不变,小于100的衰减,大于100的值强调频段。
LED亮度
矩阵的亮度在代码中预设为 32(BRIGHTNESS 常量)。WS2812B矩阵的最大亮度值(在纸上)是 255,但值已经大于 100,不幸的是,LED 灯从白色变成淡黄色,可能需要通过两根中央的红色和黑色电线而不是在右侧连接器上为矩阵供电。
我还在努力......
最后,如果使用最大亮度64,1A电源可能就足够了,否则2A是必不可少的。
未来表达
我正在开发一个使用 OpenMusicLabs FHT 库的新版本,结果证明它比 Arduino FFT 快很多倍。
敬请期待。:)
请原谅我的英语不好,我用了谷歌翻译器。

【Arduino 动手做】RGB 32 频段音频频谱可视化器图1

【Arduino 动手做】RGB 32 频段音频频谱可视化器图2

【Arduino 动手做】RGB 32 频段音频频谱可视化器图3

【Arduino 动手做】RGB 32 频段音频频谱可视化器图4

驴友花雕  中级技神
 楼主|

发表于 昨天 19:32

【Arduino 动手做】RGB 32 频段音频频谱可视化器

项目代码

  1. /*
  2.   Copyright (c) 2019 Shajeeb TM
  3.   Permission is hereby granted, free of charge, to any person obtaining a copy
  4.   of this software and associated documentation files (the "Software"), to deal
  5.   in the Software without restriction, including without limitation the rights
  6.   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  7.   copies of the Software, and to permit persons to whom the Software is
  8.   furnished to do so, subject to the following conditions:
  9.   The above copyright notice and this permission notice shall be included in all
  10.   copies or substantial portions of the Software.
  11.   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  12.   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  13.   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  14.   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  15.   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  16.   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  17.   SOFTWARE.
  18.   WS2812B Led Matrix vesion by Janux
  19. */
  20. #include <arduinoFFT.h>
  21. #include <SPI.h>
  22. #include <Adafruit_NeoPixel.h>
  23. #define SAMPLES 64        //Must be a power of 2
  24. #define  xres 32          // Total number of  columns in the display, must be <= SAMPLES/2
  25. #define  yres 8           // Total number of  rows in the display
  26. #define ledPIN 6          // pint to control Led Matrix
  27. #define NUM_LEDS (xres * yres)
  28. #define BRIGHTNESS 32
  29. #define buttonPin 5       // the number of the pushbutton pin to change displaycolor
  30. byte yvalue;
  31. byte displaycolumn, displayvalue;
  32. int peaks[xres];
  33. byte state = HIGH;           // the current reading from the input pin
  34. byte previousState = LOW;    // the previous reading from the input pin
  35. byte displaycolor = 0;
  36. //Arrays for samplig
  37. double vReal[SAMPLES];
  38. double vImag[SAMPLES];
  39. byte data_avgs[xres];
  40. arduinoFFT FFT = arduinoFFT(); // FFT object
  41. unsigned long lastDebounceTime = 0;   // the last time the output pin was toggled
  42. unsigned long debounceDelay = 100;    // the debounce time; increase if the output flickers
  43. // Parameter 1 = number of leds in matrix
  44. // Parameter 2 = pin number (most are valid)
  45. // Parameter 3 = pixel type flags, add together as needed:
  46. //   NEO_KHZ800  800 KHz bitstream (most NeoPixel products w/WS2812 LEDs)
  47. //   NEO_KHZ400  400 KHz (classic 'v1' (not v2) FLORA pixels, WS2811 drivers)
  48. //   NEO_GRB     Pixels are wired for GRB bitstream (most NeoPixel products)
  49. //   NEO_RGB     Pixels are wired for RGB bitstream (v1 FLORA pixels, not v2)
  50. Adafruit_NeoPixel pixel = Adafruit_NeoPixel(NUM_LEDS, ledPIN, NEO_GRB + NEO_KHZ800);
  51. // EQ filter to attenuates bass and improves treble
  52. // Useful on PC sound card which usually has many bass and poor high frequency
  53. bool EQ_ON = true; // set to false to disable eq
  54. byte eq[32] = {50, 55, 60, 70, 75, 80, 85, 95,
  55.                100, 100, 100, 100, 100, 100, 100, 100,
  56.                100, 100, 100, 100, 100, 100, 100, 100,
  57.                115, 125, 140, 160, 185, 200, 225, 255
  58.               };
  59. //Define color for single led, used in setColumn function, 0 for custom color
  60. //Color are calculated by Wheel function, see below
  61. byte colors[][8] = {
  62.   {170, 160, 150, 140, 130, 120, 1, 1},
  63.   {1, 5, 10, 15, 20, 25, 90, 90},
  64.   {90, 85, 80, 75, 70, 65, 1, 1},
  65.   {90, 90, 90, 30, 30, 30, 1, 1},
  66.   {170, 160, 150, 140, 130, 120, 0, 0},
  67.   {170, 160, 150, 140, 130, 120, 1, 1},
  68.   {170, 160, 150, 140, 130, 120, 1, 1}
  69. };
  70. void setup() {
  71.   
  72.   pixel.begin();  
  73.   pixel.setBrightness(BRIGHTNESS);
  74.   // Begin FFT operations
  75.   ADCSRA = 0b11100101;      // set ADC to free running mode and set pre-scalar to 32 (0xe5)
  76.   ADMUX = 0b00000000;       // use pin A0 and external voltage reference
  77. }
  78. void loop() {
  79.    
  80.   // ++ Sampling
  81.   for (int i = 0; i < SAMPLES; i++) {
  82.     while (!(ADCSRA & 0x10));       // wait for ADC to complete current conversion ie ADIF bit set
  83.     ADCSRA = 0b11110101 ;           // clear ADIF bit so that ADC can do next operation (0xf5)
  84.     int value = ADC - 512 ;         // Read from ADC and subtract DC offset caused value   
  85.     vReal[i] = value / 8;           // Copy to bins after compressing
  86.     vImag[i] = 0;
  87.   }
  88.   FFT.Windowing(vReal, SAMPLES, FFT_WIN_TYP_HAMMING, FFT_FORWARD);
  89.   FFT.Compute(vReal, vImag, SAMPLES, FFT_FORWARD);
  90.   FFT.ComplexToMagnitude(vReal, vImag, SAMPLES);
  91.   
  92.   // -- FFT
  93.   // ++ re-arrange FFT result to match with no. of columns on display (xres)
  94.   int step = (SAMPLES / 2) / xres;
  95.   int c = 0;
  96.   for (int i = 0; i < (SAMPLES / 2); i += step) {
  97.     data_avgs[c] = 0;
  98.     for (int k = 0 ; k < step ; k++) {
  99.       data_avgs[c] = data_avgs[c] + vReal[i + k];
  100.     }
  101.     data_avgs[c] = data_avgs[c] / step;
  102.     c++;
  103.   }
  104.   // ++ send to display according measured value
  105.   for (int i = 0; i <xres; i++) {
  106.     if (EQ_ON)
  107.       data_avgs[i] = data_avgs[i] * (float)(eq[i]) / 100; //apply eq filter
  108.     data_avgs[i] = constrain(data_avgs[i], 0, 80);        // set max & min values for buckets to 0-80
  109.     data_avgs[i] = map(data_avgs[i], 0, 80, 0, yres);     // remap averaged values to yres 0-8
  110.     yvalue = data_avgs[i];
  111.     peaks[i] = peaks[i] - 1;                              // decay by one light
  112.     if (yvalue > peaks[i]) peaks[i] = yvalue;             //save peak if > previuos peak
  113.     yvalue = peaks[i];
  114.     displaycolumn = i;
  115.     displayvalue = yvalue;
  116.     setColumn(displaycolumn, displayvalue);               // draw buckets
  117.   }
  118.   pixel.show();                                           // show buckets
  119.   displaycolorChange();                                   // check if button pressed to change color mode
  120. }
  121. //-----------------------------------------------------------------
  122. // Light leds of x column according to y value
  123. void setColumn(byte x, byte y) {
  124.   byte led, i;
  125.   for (i = 0; i < yres; i++) {
  126.     led = GetLedFromMatrix(x, i); //retrieve current led by x,y coordinates
  127.     if (peaks[x] > i) {
  128.       switch (displaycolor) {
  129.         case 4:
  130.           //put zero 0 on array value to customize peaks color
  131.           if (colors[displaycolor][i] > 0) {
  132.             //normal color defined on color array
  133.             pixel.setPixelColor(led, Wheel(colors[displaycolor][i]));
  134.           }
  135.           else {
  136.             //custom color for peaks only with 0 on array value
  137.             pixel.setPixelColor(led, 255, 255, 255); //Led number, R, G, B values
  138.           }
  139.           break;
  140.         case 5:
  141.           //change color by column
  142.           pixel.setPixelColor(led, Wheel(x * 16));
  143.           break;
  144.         case 6:
  145.           //change color by row         
  146.           pixel.setPixelColor(led, Wheel(i * 36));
  147.           break;
  148.         default:
  149.           //display color set -> displaycolor from 0 to 3
  150.           //color are defined on color array
  151.           pixel.setPixelColor(led, Wheel(colors[displaycolor][i]));
  152.       }//END SWITCH
  153.     }
  154.     else {
  155.       pixel.setPixelColor(led, 0);
  156.     }
  157.   }
  158. }
  159. //======================================================================
  160. // Calculate a led number by x,y coordinates
  161. // valid for WS2812B with serpentine layout placed in horizzontal
  162. // and zero led at bottom right (input connector on the right side)
  163. // input value: x=0-31, y=0-7, return a led number from 0 to 255
  164. //========================================================================
  165. byte GetLedFromMatrix(byte x, byte y) {
  166.   x = xres - x - 1;
  167.   if (x & 0x01) {
  168.     //Odd columns increase backwards
  169.     return ((x + 1) * yres - y - 1);
  170.   }
  171.   else {
  172.     //Even columns increase normally
  173.     return ((x + 1) * yres - yres + y);
  174.   }
  175. }
  176. //========================================================================
  177. void displaycolorChange() {
  178.   int reading = digitalRead(buttonPin);
  179.   if (reading == HIGH && previousState == LOW && millis() - lastDebounceTime > debounceDelay) // works only when pressed
  180.   {
  181.     displaycolor++;
  182.     if (displaycolor > 6) displaycolor = 0;
  183.     lastDebounceTime = millis();
  184.   }
  185.   previousState = reading;
  186. }
  187. /* Utility from Adafruit Neopixel demo sketch
  188.    Input a value 0 to 255 to get a color value.
  189.    The colours are a transition R - G - B - back to R.*/
  190. unsigned long Wheel(byte WheelPos) {
  191.   WheelPos = 255 - WheelPos;
  192.   if (WheelPos < 85) {
  193.     return pixel.Color(255 - WheelPos * 3, 0, WheelPos * 3);
  194.   }
  195.   if (WheelPos < 170) {
  196.     WheelPos -= 85;
  197.     return pixel.Color(0, WheelPos * 3, 255 - WheelPos * 3);
  198.   }
  199.   WheelPos -= 170;
  200.   return pixel.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
  201. }
复制代码


回复

使用道具 举报

驴友花雕  中级技神
 楼主|

发表于 昨天 19:33

【Arduino 动手做】RGB 32 频段音频频谱可视化器

【Arduino 动手做】RGB 32 频段音频频谱可视化器
项目链接:https://www.hackster.io/janux/rg ... m-visualizer-0f26e0
项目作者:贾努克斯

项目代码:https://www.hackster.io/code_files/451978/download
PCB 文件:https://hacksterio.s3.amazonaws. ... yzer_lX4Dv4Pta2.zip

【Arduino 动手做】RGB 32 频段音频频谱可视化器图1

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

为本项目制作心愿单
购买心愿单
心愿单 编辑
[[wsData.name]]

硬件清单

  • [[d.name]]
btnicon
我也要做!
点击进入购买页面
上海智位机器人股份有限公司 沪ICP备09038501号-4 备案 沪公网安备31011502402448

© 2013-2025 Comsenz Inc. Powered by Discuz! X3.4 Licensed

mail