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:
@@ -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
66
data/www/spectrum.html
Normal 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
5
partitions.csv
Normal 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
|
||||
|
@@ -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
|
||||
|
||||
@@ -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
|
||||
22
src/main.cpp
22
src/main.cpp
@@ -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();
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user