Changes to be committed:

modified:   data/www/index.html
	new file:   data/www/spectrum.html
	new file:   partitions.csv
	modified:   platformio.ini
	deleted:    src/NoteMappings copy.h
	modified:   src/main.cpp
	modified:   src/web_server.cpp
	modified:   src/web_server.h
This commit is contained in:
2025-04-16 18:16:20 +02:00
parent 3031f75836
commit 438fd59037
8 changed files with 137 additions and 52 deletions

View File

@@ -67,7 +67,8 @@
dashboard: '/dashboard.html',
wifi: '/wifi.html',
midi: '/midi.html',
system: '/system.html'
system: '/system.html',
spectrum: '/spectrum.html' // Added spectrum page
};
document.querySelectorAll('.menu-item').forEach(item => {
@@ -79,6 +80,19 @@
});
});
// Add spectrum menu item
const spectrumMenuItem = document.createElement('div');
spectrumMenuItem.className = 'menu-item';
spectrumMenuItem.dataset.page = 'spectrum';
spectrumMenuItem.textContent = 'Spectrum';
document.querySelector('.sidemenu').appendChild(spectrumMenuItem);
spectrumMenuItem.addEventListener('click', () => {
document.querySelectorAll('.menu-item').forEach(i => i.classList.remove('active'));
spectrumMenuItem.classList.add('active');
document.getElementById('contentFrame').src = pages.spectrum;
});
// Load dashboard by default
document.getElementById('contentFrame').src = pages.dashboard;
</script>

66
data/www/spectrum.html Normal file
View File

@@ -0,0 +1,66 @@
<!DOCTYPE html>
<html>
<head>
<title>Audio Spectrum</title>
<style>
body {
margin: 0;
padding: 0;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
background: #f8f9fa;
font-family: Arial, sans-serif;
}
canvas {
border: 1px solid #ccc;
}
</style>
</head>
<body>
<canvas id="spectrumCanvas" width="800" height="400"></canvas>
<script>
const canvas = document.getElementById('spectrumCanvas');
const ctx = canvas.getContext('2d');
function drawSpectrum(data) {
ctx.clearRect(0, 0, canvas.width, canvas.height);
// Draw axis labels
ctx.fillStyle = 'black';
ctx.font = '16px Arial';
ctx.fillText('Frequency/Note', canvas.width / 2 - 50, canvas.height - 10);
ctx.save();
ctx.translate(10, canvas.height / 2);
ctx.rotate(-Math.PI / 2);
ctx.fillText('Amplitude', -50, 0);
ctx.restore();
// Draw spectrum bars
const barWidth = canvas.width / data.length;
data.forEach((value, index) => {
const barHeight = value * canvas.height;
ctx.fillStyle = 'rgb(50, 150, 250)';
ctx.fillRect(index * barWidth, canvas.height - barHeight, barWidth, barHeight);
});
// Draw legend
ctx.fillStyle = 'black';
ctx.fillRect(10, 10, 20, 20);
ctx.fillStyle = 'rgb(50, 150, 250)';
ctx.fillRect(12, 12, 16, 16);
ctx.fillStyle = 'black';
ctx.font = '14px Arial';
ctx.fillText('Amplitude', 40, 25);
}
// Simulate spectrum data for testing
setInterval(() => {
const testData = Array.from({ length: 64 }, () => Math.random());
drawSpectrum(testData);
}, 100);
</script>
</body>
</html>

5
partitions.csv Normal file
View File

@@ -0,0 +1,5 @@
# Name, Type, SubType, Offset, Size, Flags
nvs, data, nvs, 0x9000, 0x5000,
otadata, data, ota, 0xe000, 0x2000,
app0, app, ota_0, 0x10000, 0x2F0000,
spiffs, data, spiffs, 0x300000,0x100000
1 # Name, Type, SubType, Offset, Size, Flags
2 nvs, data, nvs, 0x9000, 0x5000,
3 otadata, data, ota, 0xe000, 0x2000,
4 app0, app, ota_0, 0x10000, 0x2F0000,
5 spiffs, data, spiffs, 0x300000,0x100000

View File

@@ -18,7 +18,7 @@ board_build.flash_mode = qio
board_build.psram_type = qio
board_upload.flash_size = 4MB
board_upload.maximum_size = 4194304
board_build.partitions = default.csv
board_build.partitions = partitions.csv # Use custom partition table
build_flags = -DARDUINO_USB_CDC_ON_BOOT=1
-DBOARD_HAS_PSRAM
-DARDUINO_ESP32S3_DEV
@@ -33,7 +33,7 @@ monitor_filters = esp32_exception_decoder
lib_deps =
fastled/FastLED@^3.9.4
https://github.com/tzapu/WiFiManager.git
kosme/arduinoFFT@^2.0.4
kosme/arduinoFFT@^2.0.4
https://github.com/me-no-dev/ESPAsyncWebServer.git
https://github.com/me-no-dev/AsyncTCP.git
; h2zero/NimBLE-Arduino@^1.4.1

View File

@@ -1,43 +0,0 @@
// NoteMappings.h
#ifndef NOTEMAPPINGS_H
#define NOTEMAPPINGS_H
#include <map>
#include <string>
// Frequency to Note Map (simplified for illustration)
std::map<double, std::string> frequencyToNoteMap = {
{16.00, "C1"}, {32.00, "C#1"}, {33.08, "D1"}, {34.65, "D#1"}, {36.71, "E1"},
{38.89, "F1"}, {41.20, "F#1"}, {43.65, "G1"}, {46.25, "G#1"}, {49.00, "A1"},
{51.91, "A#1"}, {55.00, "B1"}, {58.27, "C2"}, {61.74, "C#2"}, {65.41, "D2"},
{69.30, "D#2"}, {73.42, "E2"}, {77.78, "F2"}, {82.41, "F#2"}, {87.31, "G2"},
{92.50, "G#2"}, {98.00, "A2"}, {103.83, "A#2"}, {110.00, "B2"},
{116.54, "C3"}, {123.47, "C#3"}, {130.81, "D3"}, {138.59, "D#3"},
{146.83, "E3"}, {155.56, "F3"}, {164.81, "F#3"}, {174.61, "G3"},
{184.99, "G#3"}, {195.99, "A3"}, {207.65, "A#3"}, {220.00, "B3"},
{233.08, "C4"}, {246.94, "C#4"}, {261.63, "D4"}, {277.18, "D#4"},
{293.66, "E4"}, {311.13, "F4"}, {329.63, "F#4"}, {349.23, "G4"},
{369.99, "G#4"}, {392.00, "A4"}, {415.30, "A#4"}, {440.00, "B4"},
{466.16, "C5"}, {493.88, "C#5"}, {523.25, "D5"}, {554.37, "D#5"},
{587.33, "E5"}, {622.25, "F5"}, {659.25, "F#5"}, {698.46, "G5"},
{739.99, "G#5"}, {783.99, "A5"}, {830.61, "A#5"}, {880.00, "B5"}
};
// Note to MIDI Number Map
std::map<std::string, byte> noteToMidiMap = {
{"C1", 24}, {"C#1", 25}, {"D1", 26}, {"D#1", 27}, {"E1", 28},
{"F1", 29}, {"F#1", 30}, {"G1", 31}, {"G#1", 32}, {"A1", 33},
{"A#1", 34}, {"B1", 35}, {"C2", 36}, {"C#2", 37}, {"D2", 38},
{"D#2", 39}, {"E2", 40}, {"F2", 41}, {"F#2", 42}, {"G2", 43},
{"G#2", 44}, {"A2", 45}, {"A#2", 46}, {"B2", 47}, {"C3", 48},
{"C#3", 49}, {"D3", 50}, {"D#3", 51}, {"E3", 52}, {"F3", 53},
{"F#3", 54}, {"G3", 55}, {"G#3", 56}, {"A3", 57}, {"A#3", 58},
{"B3", 59}, {"C4", 60}, {"C#4", 61}, {"D4", 62}, {"D#4", 63},
{"E4", 64}, {"F4", 65}, {"F#4", 66}, {"G4", 67}, {"G#4", 68},
{"A4", 69}, {"A#4", 70}, {"B4", 71}, {"C5", 72}, {"C#5", 73},
{"D5", 74}, {"D#5", 75}, {"E5", 76}, {"F5", 77}, {"F#5", 78},
{"G5", 79}, {"G#5", 80}, {"A5", 81}
};
#endif

View File

@@ -7,6 +7,11 @@
#include "esp_info.h"
#include "led_control.h"
#include "web_server.h"
#include "audio_input.h"
#include "fft_processing.h"
#include "midi.h"
#include "ble.h"
WiFiManager wm; // Global WiFiManager instance
@@ -14,8 +19,9 @@ void configModeCallback(WiFiManager *myWiFiManager) {
Serial.println("Entered config mode");
Serial.println("AP IP: " + WiFi.softAPIP().toString());
Serial.println("AP SSID: " + myWiFiManager->getConfigPortalSSID());
// Start web server in AP mode
startAccessPoint();
// Start WiFiManager's configuration portal
wm.startConfigPortal("Audio2MIDI_AP");
}
bool setupWiFi() {
@@ -73,10 +79,20 @@ void setup() {
if (!setupWiFi()) {
ESP.restart();
}
if (!initI2S()) {
Serial.println("I2S initialization failed!");
return;
}
setupBLE();
}
void loop() {
handleDNS(); // Process DNS requests for captive portal
ledCycle();
delay(10); // Small delay to prevent watchdog triggers
readAudioData();
handleFFT();
processFFTData();
}

View File

@@ -6,6 +6,12 @@ AsyncWebServer server(80);
DNSServer dnsServer;
bool isAPMode = false;
void restartWebServer() {
server.end(); // Stop the current server
setupWebServer(); // Reinitialize the server
startWebServer(); // Start the server again
}
void startAccessPoint() {
WiFi.softAP("Audio2MIDI_AP");
IPAddress IP = WiFi.softAPIP();
@@ -17,11 +23,16 @@ void startAccessPoint() {
isAPMode = true;
// Start the web server
setupWebServer();
startWebServer();
restartWebServer();
}
void setupWebServer() {
// Ensure SPIFFS is mounted
if (!SPIFFS.begin(true)) {
Serial.println("[ERROR] Failed to mount SPIFFS");
return;
}
// Add CORS headers to all responses
DefaultHeaders::Instance().addHeader("Access-Control-Allow-Origin", "*");
DefaultHeaders::Instance().addHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
@@ -49,6 +60,19 @@ void setupWebServer() {
request->send(response);
});
// API endpoint to reset WiFi settings
server.on("/api/wifi/reset", HTTP_POST, [](AsyncWebServerRequest *request) {
wm.resetSettings(); // Call resetSettings directly since it returns void
request->send(200, "application/json", "{\"message\":\"WiFi settings reset successfully.\"}");
});
// API endpoint for system factory reset
server.on("/api/system/factory-reset", HTTP_GET, [](AsyncWebServerRequest *request) {
request->send(200, "application/json", "{\"message\":\"Factory reset initiated. Device will restart.\"}");
delay(1000); // Allow time for the response to be sent
ESP.restart(); // Restart the device
});
// Root route with debug logging
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) {
Serial.print("Handling root request from IP: ");
@@ -59,7 +83,7 @@ void setupWebServer() {
request->send(SPIFFS, "/www/index.html", "text/html");
} else {
Serial.println("index.html not found!");
request->send(200, "text/plain", "Welcome to Audio2MIDI!");
request->send(404, "text/plain", "index.html not found");
}
});
@@ -108,6 +132,7 @@ void setupWebServer() {
// Catch-all handler for captive portal in AP mode
server.onNotFound([](AsyncWebServerRequest *request) {
Serial.printf("Handle Not Found: %s\n", request->url().c_str());
if (isAPMode) {
request->redirect("/");
} else {

View File

@@ -1,6 +1,7 @@
#ifndef WEB_SERVER_H
#define WEB_SERVER_H
#include <WiFiManager.h>
#include <ESPAsyncWebServer.h>
#include <DNSServer.h>
@@ -10,5 +11,6 @@ void startWebServer();
void handleDNS();
extern AsyncWebServer server;
extern DNSServer dnsServer;
extern WiFiManager wm; // Declare the global WiFiManager instance
#endif