/*
// --- LIBRERÍAS COMUNES ---
#include <Wire.h>
#include <arduinoFFT.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
// --- Configuraciones de Hardware ---
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
#define OLED_ADDR 0x3C
// ---> CAMBIO: Se elimina la definición del pin del canal derecho.
// ---> CAMBIO: Se renombra el pin para mayor claridad.
#define AUDIO_IN_PIN 36 // Pin de entrada de Audio (ADC1_CH0 en ESP32)
// --- Parámetros de la FFT ---
#define SAMPLES 128
#define SAMPLING_FREQUENCY 40000.0
// ---> CAMBIO: Se ajusta la amplitud para la visualización a pantalla completa.
// Este valor es para la sensibilidad. Un número más bajo = barras más altas.
#define AMPLITUDE 1000
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
// ---> CAMBIO: Se eliminan los arrays para el canal derecho.
// ---> CAMBIO: Se renombran los arrays restantes para no usar el sufijo 'L'.
double vReal[SAMPLES], vImag[SAMPLES];
// ---> CAMBIO: Se elimina el objeto FFT para el canal derecho.
// ---> CAMBIO: Se renombra el objeto FFT restante.
ArduinoFFT<double> fft = ArduinoFFT<double>(vReal, vImag, SAMPLES, SAMPLING_FREQUENCY);
void setup() {
display.begin(SSD1306_SWITCHCAPVCC, OLED_ADDR);
display.clearDisplay();
display.display();
}
void loop() {
// --- 1. Muestreo de la señal de audio ---
for (int i = 0; i < SAMPLES; i++) {
// ---> CAMBIO: Se leen los datos solo del único pin de entrada.
// El valor 2048.0 es para centrar la señal de ADC (que va de 0 a 4095 en ESP32).
vReal[i] = (double)analogRead(AUDIO_IN_PIN) - 2048.0;
vImag[i] = 0.0;
}
// --- 2. Procesamiento FFT ---
// ---> CAMBIO: Se realizan los cálculos solo para la única señal.
fft.windowing(FFT_WIN_TYP_HAMMING, FFT_FORWARD);
fft.compute(FFT_FORWARD);
fft.complexToMagnitude();
// --- 3. Visualización en la Pantalla OLED ---
display.clearDisplay();
// ---> CAMBIO: La visualización ahora usa toda la altura de la pantalla.
// Se dibujan SAMPLES / 2 barras, ya que la otra mitad de la FFT es un espejo.
int displayBins = SAMPLES / 2;
for (int i = 2; i < displayBins; i++) { // Se empieza en i=2 para ignorar el ruido DC.
// Calcula la altura de la barra de frecuencia.
int magnitude = vReal[i] / AMPLITUDE;
// Limita la altura de la barra a la altura de la pantalla.
magnitude = constrain(magnitude, 0, SCREEN_HEIGHT);
// Dibuja la barra vertical.
// El punto de inicio es la base de la pantalla (SCREEN_HEIGHT - 1)
// El punto final es la base menos la altura de la barra.
display.drawLine(
i * 2, // Posición X (2 píxeles de ancho por barra)
SCREEN_HEIGHT - 1, // Y inicial (base de la pantalla)
i * 2, // Posición X
SCREEN_HEIGHT - 1 - magnitude, // Y final (hacia arriba)
WHITE
);
}
display.display();
}
*/
// --- LIBRERÍAS COMUNES ---
#include <Wire.h>
#include <arduinoFFT.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
// --- Configuraciones de Hardware ---
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
#define OLED_ADDR 0x3C
#define AUDIO_IN_PIN 36 // Pin de entrada de Audio (ADC1_CH0 en ESP32)
// --- Parámetros de la FFT ---
#define SAMPLES 128
#define SAMPLING_FREQUENCY 40000.0
// Este valor es para la sensibilidad. Un número más bajo = barras más altas.
#define AMPLITUDE 1000
// --- Parámetros de la Visualización del Espectro ---
// ---> NUEVO: Se definen el rango de frecuencia y los "bins" correspondientes a mostrar.
#define MAX_FREQ 15000.0
const double FREQ_RESOLUTION = SAMPLING_FREQUENCY / SAMPLES; // Aprox. 312.5 Hz por bin
const int MIN_BIN_TO_DISPLAY = 1; // Empezamos en el bin 1 para ignorar DC (cubre de 0 a 312.5 Hz)
const int MAX_BIN_TO_DISPLAY = (int)(MAX_FREQ / FREQ_RESOLUTION); // Bin para 15kHz (aprox. bin 48)
#define SCALE_HEIGHT 10 // Altura en píxeles reservada para la escala de Hz.
#define GRAPH_HEIGHT (SCREEN_HEIGHT - SCALE_HEIGHT) // Altura para las barras del analizador.
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
double vReal[SAMPLES], vImag[SAMPLES];
ArduinoFFT<double> fft = ArduinoFFT<double>(vReal, vImag, SAMPLES, SAMPLING_FREQUENCY);
void setup() {
display.begin(SSD1306_SWITCHCAPVCC, OLED_ADDR);
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(WHITE);
display.display();
}
void loop() {
// --- 1. Muestreo de la señal de audio ---
for (int i = 0; i < SAMPLES; i++) {
vReal[i] = (double)analogRead(AUDIO_IN_PIN) - 2048.0;
vImag[i] = 0.0;
}
// --- 2. Procesamiento FFT ---
fft.windowing(FFT_WIN_TYP_HAMMING, FFT_FORWARD);
fft.compute(FFT_FORWARD);
fft.complexToMagnitude();
// --- 3. Visualización en la Pantalla OLED ---
display.clearDisplay();
// ---> MODIFICADO: Bucle de dibujo para escalar el rango de frecuencia deseado a todo el ancho de la pantalla.
// En lugar de iterar por cada bin, iteramos por cada columna de píxeles de la pantalla.
for (int x = 0; x < SCREEN_WIDTH; x++) {
// Mapeamos la posición del píxel (x) al bin de frecuencia correspondiente.
// Esto "estira" los bins desde MIN_BIN_TO_DISPLAY hasta MAX_BIN_TO_DISPLAY para que ocupen toda la pantalla.
int bin = map(x, 0, SCREEN_WIDTH - 1, MIN_BIN_TO_DISPLAY, MAX_BIN_TO_DISPLAY);
// Calcula la altura de la barra de frecuencia.
int magnitude = vReal[bin] / AMPLITUDE;
magnitude = constrain(magnitude, 0, GRAPH_HEIGHT);
// Dibuja la barra vertical.
display.drawLine(
x, // Posición X (ahora es cada píxel)
GRAPH_HEIGHT - 1, // Y inicial (base del gráfico)
x, // Posición X
GRAPH_HEIGHT - 1 - magnitude, // Y final (hacia arriba)
WHITE
);
}
// Dibuja la escala de frecuencia en la parte inferior.
drawFrequencyScale();
display.display();
}
// ---> MODIFICADO: Función para dibujar la escala de Hz adaptada al nuevo rango.
void drawFrequencyScale() {
int textY = SCREEN_HEIGHT - 7;
display.drawFastHLine(0, GRAPH_HEIGHT, SCREEN_WIDTH, WHITE);
// --- Calcula la posición X para cada etiqueta de frecuencia usando el mapeo ---
// Para cada frecuencia (ej. 5000 Hz), encontramos su bin y luego mapeamos ese bin a una posición X.
// Etiqueta 1 kHz
int bin_1k = (int)(1000 / FREQ_RESOLUTION);
int x_1k = map(bin_1k, MIN_BIN_TO_DISPLAY, MAX_BIN_TO_DISPLAY, 0, SCREEN_WIDTH - 1);
display.setCursor(x_1k, textY);
display.print("1k");
display.drawFastVLine(x_1k, GRAPH_HEIGHT, 3, WHITE);
// Etiqueta 5 kHz
int bin_5k = (int)(5000 / FREQ_RESOLUTION);
int x_5k = map(bin_5k, MIN_BIN_TO_DISPLAY, MAX_BIN_TO_DISPLAY, 0, SCREEN_WIDTH - 1);
display.setCursor(x_5k + 2, textY);
display.print("5k");
display.drawFastVLine(x_5k, GRAPH_HEIGHT, 3, WHITE);
// Etiqueta 10 kHz
int bin_10k = (int)(10000 / FREQ_RESOLUTION);
int x_10k = map(bin_10k, MIN_BIN_TO_DISPLAY, MAX_BIN_TO_DISPLAY, 0, SCREEN_WIDTH - 1);
display.setCursor(x_10k - 4, textY);
display.print("10k");
display.drawFastVLine(x_10k, GRAPH_HEIGHT, 3, WHITE);
// Etiqueta 15 kHz (límite superior)
// La movemos un poco a la izquierda para que el texto "15k" quepa en la pantalla.
display.setCursor(SCREEN_WIDTH - 18, textY);
display.print("15k");
display.drawFastVLine(SCREEN_WIDTH - 1, GRAPH_HEIGHT, 3, WHITE);
}