#include <Wire.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
// --- Pines de entrada de Audio para ESP32 ---
#define audioInL 36 // Canal Izquierdo (ADC1_CH0)
#define audioInR 39 // Canal Derecho (ADC1_CH3)
// --- Parámetros de Muestreo ---
#define SAMPLES 256
// --- Parámetros de la Barra de Nivel ---
#define BAR_START_X 18
#define BAR_MAX_WIDTH 108
#define BAR_HEIGHT 15
#define BAR_Y_L 12
#define BAR_Y_R 37
// --- Parámetros de los Segmentos de la Barra ---
#define SEGMENT_WIDTH 4
#define SEGMENT_GAP 2
// --- UMBRALES DE NIVEL (VALORES DE ADC PICO-A-PICO de 0 a 4095) ---
// *** ¡ESTOS SON LOS VALORES MÁS IMPORTANTES A CALIBRAR! ***
// Ajusta estos umbrales según la señal de audio de tu fuente.
// Corresponden a los niveles donde la barra cambia de "color".
#define LEVEL_YELLOW 2800 // Nivel para "0dB" (empieza zona amarilla)
#define LEVEL_ORANGE 3500 // Nivel para "+6dB" (empieza zona naranja)
#define LEVEL_RED 3900 // Nivel para "+9dB" (empieza zona roja/clipping)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
// Variables para las posiciones en píxeles de los umbrales
int yellow_pixel_start;
int orange_pixel_start;
int red_pixel_start;
void setup() {
Serial.begin(115200);
pinMode(audioInL, INPUT);
pinMode(audioInR, INPUT);
if(!display.begin(SSD1306_SWITCHCAPVCC, OLED_ADDR)) {
Serial.println(F("Fallo al iniciar SSD1306"));
for(;;);
}
// Pre-calcular la posición en píxeles de cada umbral para eficiencia
yellow_pixel_start = BAR_START_X + map(LEVEL_YELLOW, 0, 4095, 0, BAR_MAX_WIDTH);
orange_pixel_start = BAR_START_X + map(LEVEL_ORANGE, 0, 4095, 0, BAR_MAX_WIDTH);
red_pixel_start = BAR_START_X + map(LEVEL_RED, 0, 4095, 0, BAR_MAX_WIDTH);
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(WHITE);
display.setCursor(0,0);
display.println("Vumetro 2-CH");
display.println("Niveles Calibrados");
display.display();
delay(2000);
}
// Función para dibujar una barra de vúmetro con zonas de nivel
void drawVuBar(int y_pos, int bar_width) {
int total_segment_width = SEGMENT_WIDTH + SEGMENT_GAP;
int num_segments = bar_width / total_segment_width;
for (int i = 0; i < num_segments; i++) {
int segment_x = BAR_START_X + (i * total_segment_width);
// La "zona" (color) está implícita por la posición del segmento
// Simplemente lo dibujamos sólido (WHITE)
display.fillRect(segment_x, y_pos, SEGMENT_WIDTH, BAR_HEIGHT, WHITE);
}
}
void loop() {
unsigned int minSampleL = 4095, maxSampleL = 0;
unsigned int minSampleR = 4095, maxSampleR = 0;
unsigned long startTime = micros();
while(micros() - startTime < 20000) { // Muestrear por 20ms
unsigned int sampleL = analogRead(audioInL);
if (sampleL < minSampleL) minSampleL = sampleL;
if (sampleL > maxSampleL) maxSampleL = sampleL;
unsigned int sampleR = analogRead(audioInR);
if (sampleR < minSampleR) minSampleR = sampleR;
if (sampleR > maxSampleR) maxSampleR = sampleR;
}
unsigned int p2p_L = maxSampleL - minSampleL;
unsigned int p2p_R = maxSampleR - minSampleR;
int barWidthL = map(p2p_L, 0, 4095, 0, BAR_MAX_WIDTH);
int barWidthR = map(p2p_R, 0, 4095, 0, BAR_MAX_WIDTH);
display.clearDisplay();
// --- Dibujar la interfaz y las escalas ---
display.setTextSize(2);
display.setTextColor(WHITE);
display.setCursor(0, BAR_Y_L);
display.print("L");
display.setCursor(0, BAR_Y_R);
display.print("R");
// Dibujar las marcas de la escala para dar contexto a los "colores"
display.setTextSize(1);
// Marca para 0dB (inicio amarillo)
display.drawFastVLine(yellow_pixel_start, 0, 8, WHITE);
display.setCursor(yellow_pixel_start - 2, 8);
display.print("0");
// Marca para +6dB (inicio naranja)
display.drawFastVLine(orange_pixel_start, 0, 8, WHITE);
display.setCursor(orange_pixel_start - 5, 8);
display.print("+6");
// Marca para +9dB (inicio rojo)
display.drawFastVLine(red_pixel_start, 0, 8, WHITE);
// Dibujar las barras para cada canal
drawVuBar(BAR_Y_L, barWidthL);
drawVuBar(BAR_Y_R, barWidthR);
display.display();
}