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

[项目] 【Arduino 动手做】32(线性)/11(伪对数)频谱分析仪

[复制链接]
该项目基于 Shajeeb 的项目,使用 Arduino 制作音频(音乐)频谱分析仪/可视化器。

这是我第一次尝试搭建Arduino项目。我对任何与音频项目相关的内容都很感兴趣。我找到了Shajeeb的音频可视化工具,尝试让显示屏上的刻度有所不同。有点像对数函数,但我只是在Excel里创建了一些(对数/指数)表格,然后在项目代码中手动实现了数据映射。

添加/修改更改显示的按钮:单条(线性刻度显示/双条-伪对数)。

希望你喜欢它,享受构建。

【Arduino 动手做】32(线性)/11(伪对数)频谱分析仪图1

【Arduino 动手做】32(线性)/11(伪对数)频谱分析仪图3

【Arduino 动手做】32(线性)/11(伪对数)频谱分析仪图2

驴友花雕  中级技神
 楼主|

发表于 4 小时前

【Arduino 动手做】32(线性)/11(伪对数)波段音频频...

项目代码

  1. // Modified code by Christian Suryanto, from (c) 2019 Shajeeb TM
  2. // HAZI TECH
  3. // Updated by Christian Suryanto
  4. //
  5. #include <arduinoFFT.h>
  6. #include <MD_MAX72xx.h>
  7. #include <SPI.h>
  8. #include <EEPROM.h>
  9. #define HARDWARE_TYPE MD_MAX72XX::FC16_HW                     // Set display type  so that  MD_MAX72xx library treets it properly
  10. #define CLK_PIN   13                                          // Clock pin to communicate with display
  11. #define DATA_PIN  11                                          // Data pin to communicate with display
  12. #define CS_PIN    10                                          // Control pin to communicate with display
  13. #define SAMPLES 64                                           // Must be a power of 2
  14. #define MAX_DEVICES  4                                        // Total number display modules
  15. #define  xres 32                                              // Total number of  columns in the display, must be <= SAMPLES/2
  16. #define  yres 8                                               // Total number of  rows in the display
  17. #define PREV 0xFF02FD // address is FFA25D but 0x is added because this is how the arduino is told that it is HEXADECIMAL.
  18. #define NEXT 0xFFC23D // control stop code
  19. #define PWR 0xFFA25D // control Power
  20. int audio_response = 35;                                      // put a value between 10 and 80. Smaller the number, higher the audio response
  21. double vReal[SAMPLES];
  22. //double vReal2[SAMPLES];
  23. double vImag[SAMPLES];
  24. char data_avgs[xres];
  25. int yvalue;
  26. int displaycolumn , displayvalue;
  27. int peaks[xres];
  28. const int buttonPin = 6;                                      // the number of the pushbutton pin
  29. int state = HIGH;                                             // the current reading from the input pin
  30. int previousState = LOW;                                      // the previous reading from the input pin
  31. int displaymode;
  32. unsigned long lastDebounceTime = 0;                           // the last time the output pin was toggled
  33. unsigned long debounceDelay = 50;                             // the debounce time; increase if the output flickers
  34. int MY_ARRAY[]={0, 128, 192, 224, 240, 248, 252, 254, 255};   // default = standard pattern
  35. //int MY_MODE_1[]={0, 128, 192, 224, 240, 248, 252, 254, 255};  // standard pattern
  36. //int MY_MODE_2[]={0, 128, 64, 32, 16, 8, 4, 2, 1};             // only peak pattern
  37. //int MY_MODE_3[]={0, 128, 192, 160, 144, 136, 132, 130, 129};  // only peak +  bottom point
  38. //int MY_MODE_4[]={0, 128, 192, 160, 208, 232, 244, 250, 253};  // one gap in the top , 3rd light onwards
  39. bool EQ_ON = true; // set to false to disable eq
  40. byte eq1[32] = {40, 45, 50, 60, 65, 70, 75, 95,
  41.                110, 110, 110, 110, 110, 110, 110, 110,
  42.                130, 130, 130, 130, 130, 130, 130, 130,
  43.                145, 155, 170, 180, 215, 220, 245, 255
  44.               };
  45. byte eq2[11] = {40, 70, 75, 110, 110, 140, 145, 220, 220, 230, 250};
  46. MD_MAX72XX mx = MD_MAX72XX(HARDWARE_TYPE, CS_PIN, MAX_DEVICES);   // display object
  47. arduinoFFT FFT = arduinoFFT();                                    // FFT object
  48. void setup() {
  49.     EEPROM.update(1,1);                                           //(memory address, value), RUN THIS FOR THE FIRST TIME
  50.     displaymode = EEPROM.read(1);
  51.     //displaymode = 1;
  52.     ADCSRA = 0b11100101;                                          // set ADC to free running mode and set pre-scalar to 32 (0xe5)
  53.     ADMUX = 0b00000000;                                           // use pin A0 and external voltage reference
  54.     pinMode(buttonPin, INPUT);
  55.     mx.begin();                                                   // initialize display
  56.     mx.control(MD_MAX72XX::INTENSITY, 0);                         // set LED intensity
  57.     delay(50);                                                    // wait to get reference voltage stabilized
  58. }
  59. void loop() {
  60.    // ++ Sampling
  61.    int numData;
  62.    double rSum;
  63.    for(int i=0; i<SAMPLES; i++)
  64.     {
  65.       while(!(ADCSRA & 0x10));                                    // wait for ADC to complete current conversion ie ADIF bit set
  66.       ADCSRA = 0b11110101 ;                                       // clear ADIF bit so that ADC can do next operation (0xf5)
  67.       int value = ADC - 512 ;                                     // Read from ADC and subtract DC offset caused value
  68.       value = value / 8;
  69.       vReal[i]= value;                                          // Copy to bins after compressing
  70.       vImag[i] = 0;                        
  71.     }
  72.     // -- Sampling
  73.      //++ FFT
  74.     FFT.Windowing(vReal, SAMPLES, FFT_WIN_TYP_HAMMING, FFT_FORWARD);
  75.     FFT.Compute(vReal, vImag, SAMPLES, FFT_FORWARD);
  76.     FFT.ComplexToMagnitude(vReal, vImag, SAMPLES);
  77.     // -- FFT
  78.     int step = (SAMPLES)/xres;
  79. // re-mapping data - Customize by Christian Suryanto ///
  80.     switch (displaymode)
  81.     {
  82.     case 1 :
  83.       {
  84.         numData = 32;
  85.         data_avgs[0] = (vReal[0] + vReal[0])/2;
  86.         data_avgs[1] = (vReal[1] + vReal[63])/2;
  87.         data_avgs[2] = (vReal[2] + vReal[62])/2;
  88.         data_avgs[3] = (vReal[3] + vReal[61])/2;
  89.         data_avgs[4] = (vReal[4] + vReal[60])/2;
  90.         data_avgs[5] = (vReal[5] + vReal[59])/2;
  91.         data_avgs[6] = (vReal[6] + vReal[58])/2;
  92.         data_avgs[7] = (vReal[7] + vReal[57])/2;
  93.         data_avgs[8] = (vReal[8] + vReal[56])/2;
  94.         data_avgs[9] = (vReal[9] + vReal[55])/2;
  95.         data_avgs[10] = (vReal[10] + vReal[54])/2;
  96.         data_avgs[11] = (vReal[11] + vReal[53])/2;
  97.         data_avgs[12] = (vReal[12] + vReal[52])/2;
  98.         data_avgs[13] = (vReal[13] + vReal[51])/2;
  99.         data_avgs[14] = (vReal[14] + vReal[50])/2;
  100.         data_avgs[15] = (vReal[15] + vReal[49])/2;
  101.         data_avgs[16] = (vReal[16] + vReal[48])/2;
  102.         data_avgs[17] = (vReal[17] + vReal[47])/2;
  103.         data_avgs[18] = (vReal[18] + vReal[46])/2;
  104.         data_avgs[19] = (vReal[19] + vReal[45])/2;
  105.         data_avgs[20] = (vReal[20] + vReal[44])/2;
  106.         data_avgs[21] = (vReal[21] + vReal[43])/2;
  107.         data_avgs[22] = (vReal[22] + vReal[42])/2;
  108.         data_avgs[23] = (vReal[23] + vReal[41])/2;
  109.         data_avgs[24] = (vReal[24] + vReal[40])/2;
  110.         data_avgs[25] = (vReal[25] + vReal[39])/2;
  111.         data_avgs[26] = (vReal[26] + vReal[38])/2;
  112.         data_avgs[27] = (vReal[27] + vReal[37])/2;
  113.         data_avgs[28] = (vReal[28] + vReal[36])/2;
  114.         data_avgs[29] = (vReal[29] + vReal[35])/2;
  115.         data_avgs[30] = (vReal[30] + vReal[34])/2;
  116.         data_avgs[31] = (vReal[31] + vReal[33])/2;
  117.       }
  118.       break;
  119.     case 2 :
  120.       {
  121.         numData = 11;
  122.         data_avgs[0] = (vReal[0] + vReal[0])/2;
  123.         data_avgs[1] = (vReal[0] + vReal[0] + vReal[1] + vReal[63]) / 4;
  124.         data_avgs[2] = ( vReal[1] + vReal[63] + vReal[2] + vReal[62] + vReal[3] + vReal[61])/6;
  125.         data_avgs[3] = (vReal[2] + vReal[62] + vReal[3] + vReal[61] + vReal[4] + vReal[60])/6;
  126.         data_avgs[4] = (vReal[5] + vReal[59] + vReal[6] + vReal[58] + vReal[7] + vReal[57])/6;
  127.         data_avgs[5] = (vReal[8] + vReal[56] + vReal[9] + vReal[55] + vReal[10] + vReal[54] + vReal[11] + vReal[53])/8;
  128.         data_avgs[6] = (vReal[12] + vReal[52] + vReal[13] + vReal[51] + vReal[14] + vReal[50] + vReal[15] + vReal[49])/8;
  129.         data_avgs[7] = (vReal[16] + vReal[48] + vReal[17] + vReal[47] + vReal[18] + vReal[46])/6;
  130.         data_avgs[8] = (vReal[19] + vReal[45] + vReal[20] + vReal[44] + vReal[21] + vReal[43] + vReal[22] + vReal[42])/8;
  131.         data_avgs[9] = (vReal[23] + vReal[41] + vReal[24] + vReal[40] + vReal[25] + vReal[39] + vReal[26] + vReal[38] + vReal[27] + vReal[37])/10;
  132.         data_avgs[10] = (vReal[28] + vReal[36] + vReal[29] + vReal[35] + vReal[30] + vReal[34] + vReal[31] + vReal[33])/8;
  133.       }
  134.       break;
  135.     }
  136. // re-mapping data - Customize by Christian Suryanto ///
  137.     for(int i=0; i<numData; i++)
  138.     {
  139.       data_avgs[i] = data_avgs[i] / 2;
  140.       if (EQ_ON)
  141.         switch (displaymode)
  142.         {
  143.           case 1 : data_avgs[i] = (data_avgs[i]) * (float)(eq1[i]) / 100; //apply eq filter
  144.           break;
  145.          
  146.           case 2 : data_avgs[i] = (data_avgs[i]) * (float)(eq2[i]) / 100; //apply eq filter
  147.           break;
  148.         }
  149.       data_avgs[i] = constrain(data_avgs[i],0,audio_response);              // set max & min values for buckets
  150.       data_avgs[i] = map(data_avgs[i], 0, audio_response, 0, yres);         // remap averaged values to yres
  151.       
  152.       yvalue=data_avgs[i];
  153.       peaks[i] = peaks[i]-1;    // decay by one light
  154.       if (yvalue > peaks[i])
  155.           peaks[i] = yvalue ;
  156.       yvalue = peaks[i];   
  157.       displayvalue=MY_ARRAY[yvalue];
  158.       
  159.       switch (displaymode)
  160.       {
  161.         case 1:
  162.         {
  163.           displaycolumn=31-i;
  164.           mx.setColumn(displaycolumn, displayvalue);                // for left to right
  165.         }
  166.         break;
  167.         case 2:
  168.         {
  169.           displaycolumn=31-(3*i);
  170.           mx.setColumn(displaycolumn-1, displayvalue);                // for left to right
  171.           mx.setColumn(displaycolumn, displayvalue);                // for left to right
  172.         }
  173.         break;
  174.       }
  175.      }
  176.      // -- send to display according measured value
  177.      
  178.     displayModeChange ();                                       // check if button pressed to change display mode
  179. }
  180. void displayModeChange() {
  181.   int reading = digitalRead(buttonPin);
  182.   if (reading == HIGH && previousState == LOW && millis() - lastDebounceTime > debounceDelay) // works only when pressed
  183.   {
  184.     switch (displaymode)
  185.      {
  186.       case 1:    //       move from mode 1 to 2
  187.         displaymode = 2;
  188.         mx.clear();
  189.         delay(200);
  190.         EEPROM.update(1,2);
  191.         break;
  192.       case 2:    //       move from mode 2 to 3
  193.         displaymode = 1;
  194.         mx.clear();
  195.         delay(200);
  196.         EEPROM.update(1,1);
  197.         break;
  198.     }
  199.     lastDebounceTime = millis();
  200.   }
  201.   previousState = reading;
  202. }
复制代码


回复

使用道具 举报

驴友花雕  中级技神
 楼主|

发表于 4 小时前

【Arduino 动手做】32(线性)/11(伪对数)波段音频频...

【Arduino 动手做】32(线性)/11(伪对数)波段音频频谱分析仪
项目链接:https://www.hackster.io/chrissur ... rum-analyzer-8e8c7b
项目作者:克里苏里亚

项目代码:https://www.hackster.io/code_files/559275/download

【Arduino 动手做】32(线性)/11(伪对数)频谱分析仪图1

回复

使用道具 举报

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

本版积分规则

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

硬件清单

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

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

mail