Redesign to keepsake Memory Frame: config file based named memories with beautiful mobile web dashboard, upload wizard, and delete flow

This commit is contained in:
drjones
2026-07-04 02:18:39 -07:00
parent d23b6c245c
commit 1c5be95d4c
9 changed files with 1019 additions and 675 deletions

View File

@@ -1,20 +1,16 @@
#include "Audio_Player.h"
#include "Audio.h"
Audio audio;
TaskHandle_t audioTaskHandle = NULL;
volatile bool isAudioTaskRunning = false;
uint8_t currentVolume = 12; // 0 to 21 range
static Audio audio;
static TaskHandle_t audioTaskHandle = NULL;
static volatile bool audioTaskRunning = false;
uint16_t Audio_Count = 0;
char Audio_Names[100][100];
// FreeRTOS background task on Core 0 to run ESP32-audioI2S decode loop
void audioLoopTask(void* parameter) {
isAudioTaskRunning = true;
while (isAudioTaskRunning) {
// ── Background decode task (Core 0) ──────────────────────────────────────────
static void audioLoopTask(void* param) {
audioTaskRunning = true;
while (audioTaskRunning) {
audio.loop();
vTaskDelay(pdMS_TO_TICKS(1)); // Yield to let other RTOS tasks run
vTaskDelay(pdMS_TO_TICKS(1));
}
audioTaskHandle = NULL;
vTaskDelete(NULL);
@@ -22,25 +18,25 @@ void audioLoopTask(void* parameter) {
void initAudioPlayer() {
audio.setPinout(I2S_BCLK, I2S_LRCK, I2S_DIN);
audio.setVolume(currentVolume);
// Start the background loop task on Core 0
if (audioTaskHandle == NULL) {
xTaskCreatePinnedToCore(
audioLoopTask,
"audioLoopTask",
16384, // Increased from 8192 — ESP32-audioI2S MP3 decode needs ~12-16KB stack
NULL,
5, // Priority
&audioTaskHandle,
0 // Core 0
);
audio.setVolume(g_volume);
if (!audioTaskHandle) {
xTaskCreatePinnedToCore(audioLoopTask, "audioLoop", 16384, NULL, 5, &audioTaskHandle, 0);
}
}
void playAudio(const char* filePath) {
printf("AudioPlayer: Connecting to FS for file: %s\r\n", filePath);
audio.connecttoFS(SD_MMC, filePath);
// ── Public controls ───────────────────────────────────────────────────────────
void playAudio(const char* fullPath) {
printf("Audio: playing %s\r\n", fullPath);
audio.connecttoFS(SD_MMC, fullPath);
}
void playMemoryAudio(int memoryIndex) {
if (memoryIndex < 0 || memoryIndex >= g_memoryCount) return;
const char* audioFile = g_memories[memoryIndex].audio;
if (audioFile[0] == '\0') return; // no audio for this memory
char path[120];
snprintf(path, sizeof(path), "/audio/%s", audioFile);
playAudio(path);
}
void stopAudio() {
@@ -57,46 +53,11 @@ bool isAudioPlaying() {
void setPlayerVolume(uint8_t volume) {
if (volume > 21) volume = 21;
currentVolume = volume;
audio.setVolume(currentVolume);
printf("AudioPlayer: Volume set to %d / 21\r\n", currentVolume);
g_volume = volume;
audio.setVolume(g_volume);
printf("Audio: volume -> %d/21\r\n", g_volume);
}
uint8_t getPlayerVolume() {
return currentVolume;
}
// Case-insensitive check if filename ends with a given extension
static bool hasExtension(const char* name, const char* ext) {
size_t nLen = strlen(name);
size_t eLen = strlen(ext);
if (nLen < eLen) return false;
return strcasecmp(name + nLen - eLen, ext) == 0;
}
void Search_Audio(const char* directory) {
File Path = SD_MMC.open(directory);
if (!Path) {
printf("Path: <%s> does not exist\r\n", directory);
Audio_Count = 0;
return;
}
uint16_t fileCount = 0;
File file = Path.openNextFile();
while (file && fileCount < 100) {
if (!file.isDirectory()) {
const char* name = file.name();
// Case-insensitive extension match to handle FAT32 uppercase names
if (hasExtension(name, ".wav") || hasExtension(name, ".mp3")) {
strncpy(Audio_Names[fileCount], name, sizeof(Audio_Names[fileCount]) - 1);
Audio_Names[fileCount][sizeof(Audio_Names[fileCount]) - 1] = '\0';
fileCount++;
}
}
file = Path.openNextFile();
}
Path.close();
Audio_Count = fileCount;
printf("Found %d audio files (.mp3/.wav)\r\n", Audio_Count);
return g_volume;
}