Analyzer Spektrum Audio 32-Band Berbasis Arduino – Tampilan Linear & Pseudo-Log
Komponen & Perlengkapan
 | | × | 1 | |
 | | × | 1 | |
 | | × | 2 | |
 | | × | 3 | |
 | | × | 1 | |
 | | × | 1 | |
 | | × | 1 | |
 | | Tombol Tactile (Top Actuated) |
| × | 1 | |
 | | Header Machan 36-Posisi 1-Baris (0,1") |
| × | 1 | |
Perangkat Lunak & Layanan Online
Tentang Proyek Ini
Proyek ini menandai langkah pertama saya ke dalam elektronik audio berbasis Arduino. Terinspiri oleh audio visualizer Shajeeb, saya memperluas tampilan untuk mencakup mode linear 32-band dan mode pseudo-log 11-band. Saya membangun tabel pemetaan logaritmik kustom di Excel dan mengintegrasikannya ke dalam firmware untuk respons frekuensi yang lebih akurat.
Tombol tactile bergantian antara dua mode tampilan, memungkinkan perpindahan cepat selama performa atau eksperimen.
Bebas untuk menyesuaikan firmware atau hardware agar cocok dengan proyek kreatif Anda sendiri.
Kode Sumber
- 32_Band_LED_Spectrum_Analyzer-009.ino
32_Band_LED_Spectrum_Analyzer-009.ino Arduino
// Modified code by Christian Suryanto, based on (c) 2019 Shajeeb TM // HAZI TECH // Updated by Christian Suryanto #include <arduinoFFT.h> #include <MD_MAX72xx.h> #include <SPI.h> #include <EEPROM.h> #define HARDWARE_TYPE MD_MAX72XX::FC16_HW #define CLK_PIN 13 #define DATA_PIN 11 #define CS_PIN 10 #define SAMPLES 64 #define MAX_DEVICES 4 #define xres 32 #define yres 8 #define PREV 0xFF02FD #define NEXT 0xFFC23D #define PWR 0xFFA25D int audio_response = 35; double vReal[SAMPLES]; double vImag[SAMPLES]; char data_avgs[xres]; int yvalue; int displaycolumn , displayvalue; int peaks[xres]; const int buttonPin = 6; int state = HIGH; int previousState = LOW; int displaymode; unsigned long lastDebounceTime = 0; unsigned long debounceDelay = 50; int MY_ARRAY[]={0, 128, 192, 224, 240, 248, 252, 254, 255}; bool EQ_ON = true; byte eq1[32] = {40, 45, 50, 60, 65, 70, 75, 95, 110, 110, 110, 110, 110, 110, 110, 110, 130, 130, 130, 130, 130, 130, 130, 130, 145, 155, 170, 180, 215, 220, 245, 255}; byte eq2[11] = {40, 70, 75, 110, 110, 140, 145, 220, 220, 230, 250}; MD_MAX72XX mx = MD_MAX72XX(HARDWARE_TYPE, CS_PIN, MAX_DEVICES); arduinoFFT FFT = arduinoFFT(); void setup() { EEPROM.update(1,1); displaymode = EEPROM.read(1); ADCSRA = 0b11100101; ADMUX = 0b00000000; pinMode(buttonPin, INPUT); mx.begin(); mx.control(MD_MAX72XX::INTENSITY, 0); delay(50); } void loop() { int numData; double rSum; for(int i=0; i<SAMPLES; i++) { while(!(ADCSRA & 0x10)); ADCSRA = 0b11110101; int value = ADC - 512; value = value / 8; vReal[i] = value; vImag[i] = 0; } FFT.Windowing(vReal, SAMPLES, FFT_WIN_TYP_HAMMING, FFT_FORWARD); FFT.Compute(vReal, vImag, SAMPLES, FFT_FORWARD); FFT.ComplexToMagnitude(vReal, vImag, SAMPLES); int step = (SAMPLES)/xres; switch (displaymode) { case 1 : { numData = 32; for(int i=0; i<32; i++) data_avgs[i] = (vReal[i] + vReal[SAMPLES-1-i]) / 2; break; } case 2 : { numData = 11; data_avgs[0] = vReal[0]; data_avgs[1] = (vReal[0] + vReal[63] + vReal[1] + vReal[0]) / 4; data_avgs[2] = (vReal[1] + vReal[63] + vReal[2] + vReal[62] + vReal[3] + vReal[61]) / 6; data_avgs[3] = (vReal[2] + vReal[62] + vReal[3] + vReal[61] + vReal[4] + vReal[60]) / 6; data_avgs[4] = (vReal[5] + vReal[59] + vReal[6] + vReal[58] + vReal[7] + vReal[57]) / 6; data_avgs[5] = (vReal[8] + vReal[56] + vReal[9] + vReal[55] + vReal[10] + vReal[54] + vReal[11] + vReal[53]) / 8; data_avgs[6] = (vReal[12] + vReal[52] + vReal[13] + vReal[51] + vReal[14] + vReal[50] + vReal[15] + vReal[49]) / 8; data_avgs[7] = (vReal[16] + vReal[48] + vReal[17] + vReal[47] + vReal[18] + vReal[46]) / 6; data_avgs[8] = (vReal[19] + vReal[45] + vReal[20] + vReal[44] + vReal[21] + vReal[43] + vReal[22] + vReal[42]) / 8; data_avgs[9] = (vReal[23] + vReal[41] + vReal[24] + vReal[40] + vReal[25] + vReal[39] + vReal[26] + vReal[38] + vReal[27] + vReal[37]) / 10; data_avgs[10] = (vReal[28] + vReal[36] + vReal[29] + vReal[35] + vReal[30] + vReal[34] + vReal[31] + vReal[33]) / 8; break; } } for(int i=0; i<numData; i++) { data_avgs[i] = data_avgs[i] / 2; if (EQ_ON) { if (displaymode==1) data_avgs[i] = data_avgs[i] * eq1[i] / 100; else data_avgs[i] = data_avgs[i] * eq2[i] / 100; } data_avgs[i] = constrain(data_avgs[i],0,audio_response); data_avgs[i] = map(data_avgs[i], 0, audio_response, 0, yres); yvalue = data_avgs[i]; peaks[i] = peaks[i]-1; if (yvalue > peaks[i]) peaks[i] = yvalue; yvalue = peaks[i]; displayvalue = MY_ARRAY[yvalue]; if (displaymode==1) { displaycolumn = 31-i; mx.setColumn(displaycolumn, displayvalue); } else { displaycolumn = 31-(3*i); mx.setColumn(displaycolumn-1, displayvalue); mx.setColumn(displaycolumn, displayvalue); } } displayModeChange(); } void displayModeChange() { int reading = digitalRead(buttonPin); if (reading == HIGH && previousState == LOW && millis() - lastDebounceTime > debounceDelay) { if (displaymode==1) { displaymode = 2; mx.clear(); delay(200); EEPROM.update(1,2); } else { displaymode = 1; mx.clear(); delay(200); EEPROM.update(1,1); } lastDebounceTime = millis(); } previousState = reading; }
Skematik