[ai] quickwin memory optimiziations, wip

This commit is contained in:
Stefan Ostermann 2025-11-02 20:31:05 +01:00
parent 465e34e919
commit 3a34b1b8d0
2 changed files with 52 additions and 43 deletions

View File

@ -37,19 +37,20 @@ const std::vector<String> &DirectoryNode::getMP3Files() const
return mp3Files;
}
void DirectoryNode::setCurrentPlaying(const String mp3File)
void DirectoryNode::setCurrentPlaying(const String &mp3File)
{
currentPlaying = mp3File;
for (int i = 0; i < mp3Files.size(); i++)
for (size_t i = 0; i < mp3Files.size(); i++)
{
if (mp3Files[i] == mp3File && ids.size() > i)
{
currentPlayingId = ids[i];
break;
}
}
}
const String DirectoryNode::getCurrentPlaying() const
const String &DirectoryNode::getCurrentPlaying() const
{
return currentPlaying;
}
@ -82,7 +83,7 @@ void DirectoryNode::setSecondsPlayed(const uint32_t seconds)
secondsPlayed = seconds;
}
uint32_t DirectoryNode::getSecondsPlayed()
uint32_t DirectoryNode::getSecondsPlayed() const
{
return secondsPlayed;
}
@ -97,6 +98,9 @@ void DirectoryNode::buildDirectoryTree(const char *currentPath)
subdirectories.clear();
mp3Files.clear();
ids.clear();
subdirectories.shrink_to_fit();
mp3Files.shrink_to_fit();
ids.shrink_to_fit();
// First collect entries so we can sort them alphabetically
std::vector<String> dirNames;
@ -113,27 +117,33 @@ void DirectoryNode::buildDirectoryTree(const char *currentPath)
if (entry.isDirectory() && entry.name()[0] != '.' && strcmp(entry.name(), sys_dir))
{
dirNames.push_back(String(entry.name()));
dirNames.emplace_back(entry.name());
}
else
{
String entryName = entry.name();
if (entryName.endsWith(".mp3") || entryName.endsWith(".MP3"))
{
fileNames.push_back(entryName);
fileNames.push_back(std::move(entryName));
}
}
entry.close();
}
rootDir.close();
// Case-insensitive alphabetical sort
// Case-insensitive alphabetical sort without allocations
auto ciLess = [](const String &a, const String &b) {
String al = a;
String bl = b;
al.toLowerCase();
bl.toLowerCase();
return al.compareTo(bl) < 0;
const char* pa = a.c_str();
const char* pb = b.c_str();
while (*pa && *pb) {
char ca = *pa++;
char cb = *pb++;
if (ca >= 'A' && ca <= 'Z') ca += 'a' - 'A';
if (cb >= 'A' && cb <= 'Z') cb += 'a' - 'A';
if (ca < cb) return true;
if (ca > cb) return false;
}
return *pa < *pb;
};
std::sort(dirNames.begin(), dirNames.end(), ciLess);
std::sort(fileNames.begin(), fileNames.end(), ciLess);
@ -165,7 +175,7 @@ void DirectoryNode::buildDirectoryTree(const char *currentPath)
fullPath += "/";
fullPath += fileName;
mp3Files.push_back(fullPath);
mp3Files.push_back(std::move(fullPath));
ids.push_back(getNextId());
}
}
@ -174,7 +184,7 @@ void DirectoryNode::printDirectoryTree(int level) const
{
for (int i = 0; i < level; i++)
{
Serial.print(" ");
Serial.print(F(" "));
}
Serial.println(name);
@ -182,7 +192,7 @@ void DirectoryNode::printDirectoryTree(int level) const
{
for (int i = 0; i <= level; i++)
{
Serial.print(" ");
Serial.print(F(" "));
}
Serial.println(mp3File);
}
@ -256,15 +266,16 @@ DirectoryNode *DirectoryNode::advanceToMP3(const uint16_t id)
}
// If we get here, no song with this ID was found
Serial.println("advanceToMP3: No song found for ID: " + String(id));
Serial.print(F("advanceToMP3: No song found for ID: "));
Serial.println(id);
return nullptr;
}
DirectoryNode *DirectoryNode::advanceToMP3(const String songName)
DirectoryNode *DirectoryNode::advanceToMP3(const String &songName)
{
if (songName.isEmpty())
{
Serial.println("advanceToMP3: songName is empty");
Serial.println(F("advanceToMP3: songName is empty"));
return nullptr;
}
@ -279,8 +290,6 @@ DirectoryNode *DirectoryNode::advanceToMP3(const String songName)
// Lowercased copies for case-insensitive comparisons (FAT can uppercase names)
String lowTarget = songName;
lowTarget.toLowerCase();
String lowNormPath = normalizedPath;
lowNormPath.toLowerCase();
// First, search in the current directory's MP3 files
for (size_t i = 0; i < mp3Files.size(); i++)
@ -359,7 +368,8 @@ DirectoryNode *DirectoryNode::advanceToMP3(const String songName)
}
// If we get here, no matching song was found
Serial.println("advanceToMP3: No song found for: " + songName);
Serial.print(F("advanceToMP3: No song found for: "));
Serial.println(songName);
return nullptr;
}
@ -376,14 +386,14 @@ DirectoryNode *DirectoryNode::goToPreviousMP3(uint32_t thresholdSeconds)
// Safety check for null pointer
if (currentPlaying.isEmpty())
{
Serial.println("goToPreviousMP3: currentPlaying is empty");
Serial.println(F("goToPreviousMP3: currentPlaying is empty"));
return nullptr;
}
// If we've been playing for more than threshold seconds, restart current song
if (secondsPlayed > thresholdSeconds)
{
Serial.println("goToPreviousMP3: Restarting current song (played > threshold)");
Serial.println(F("goToPreviousMP3: Restarting current song (played > threshold)"));
return this;
}
@ -401,7 +411,7 @@ DirectoryNode *DirectoryNode::goToPreviousMP3(uint32_t thresholdSeconds)
// If current song found and not the first song, move to previous
if (currentIndex > 0)
{
Serial.print("goToPreviousMP3: Moving to previous song in same directory: ");
Serial.print(F("goToPreviousMP3: Moving to previous song in same directory: "));
Serial.println(mp3Files[currentIndex - 1]);
setCurrentPlaying(mp3Files[currentIndex - 1]);
return this;
@ -409,15 +419,15 @@ DirectoryNode *DirectoryNode::goToPreviousMP3(uint32_t thresholdSeconds)
// If we're at the first song or song not found in current directory,
// we need to find the previous song globally
Serial.println("goToPreviousMP3: At first song or song not found, looking for previous globally");
Serial.println(F("goToPreviousMP3: At first song or song not found, looking for previous globally"));
return nullptr; // Let the caller handle global previous logic
}
DirectoryNode *DirectoryNode::findPreviousMP3Globally(const String currentGlobal)
DirectoryNode *DirectoryNode::findPreviousMP3Globally(const String &currentGlobal)
{
if (currentGlobal.isEmpty())
{
Serial.println("findPreviousMP3Globally: currentGlobal is null");
Serial.println(F("findPreviousMP3Globally: currentGlobal is null"));
return nullptr;
}
@ -444,23 +454,25 @@ DirectoryNode *DirectoryNode::findPreviousMP3Globally(const String currentGlobal
DirectoryNode *prevNode = allMP3s[currentGlobalIndex - 1].first;
int prevFileIndex = allMP3s[currentGlobalIndex - 1].second;
Serial.print("findPreviousMP3Globally: Moving to previous song globally: ");
Serial.print(F("findPreviousMP3Globally: Moving to previous song globally: "));
Serial.println(prevNode->mp3Files[prevFileIndex]);
prevNode->setCurrentPlaying(prevNode->mp3Files[prevFileIndex]);
return prevNode;
}
Serial.println("findPreviousMP3Globally: No previous song found globally");
Serial.println(F("findPreviousMP3Globally: No previous song found globally"));
return nullptr;
}
void DirectoryNode::buildFlatMP3List(std::vector<std::pair<DirectoryNode *, int>> &allMP3s)
{
// Pre-reserve to reduce reallocations
allMP3s.reserve(allMP3s.size() + mp3Files.size());
// Add all MP3 files from this directory
for (size_t i = 0; i < mp3Files.size(); i++)
{
allMP3s.push_back(std::make_pair(this, i));
allMP3s.emplace_back(this, i);
}
// Recursively add MP3 files from subdirectories
@ -470,12 +482,12 @@ void DirectoryNode::buildFlatMP3List(std::vector<std::pair<DirectoryNode *, int>
}
}
const size_t DirectoryNode::getNumOfFiles()
size_t DirectoryNode::getNumOfFiles() const
{
return subdirectories.size();
}
DirectoryNode *DirectoryNode::advanceToNextMP3(const String currentGlobal)
DirectoryNode *DirectoryNode::advanceToNextMP3(const String &currentGlobal)
{
bool useFirst = false;
Serial.println(currentGlobal.c_str());
@ -534,7 +546,7 @@ DirectoryNode *DirectoryNode::advanceToNextMP3(const String currentGlobal)
// If we get here, there were no MP3 files or subdirectories left to check
currentPlaying = "";
Serial.println("no more nodes found");
Serial.println(F("no more nodes found"));
return this;
}
@ -581,6 +593,3 @@ void DirectoryNode::streamDirectoryHTML(Print &out) const {
yield(); // Final yield before completing
}
}

View File

@ -34,14 +34,14 @@ public:
const std::vector<DirectoryNode*>& getSubdirectories() const;
const std::vector<String>& getMP3Files() const;
const size_t getNumOfFiles();
size_t getNumOfFiles() const;
void setCurrentPlaying(const String mp3File);
const String getCurrentPlaying() const;
void setCurrentPlaying(const String& mp3File);
const String& getCurrentPlaying() const;
const uint16_t getCurrentPlayingId() const;
void setSecondsPlayed(const uint32_t seconds);
uint32_t getSecondsPlayed();
uint32_t getSecondsPlayed() const;
uint16_t getNextId();
@ -49,10 +49,10 @@ public:
void addMP3File(const String& mp3File);
void buildDirectoryTree(const char* currentPath);
void printDirectoryTree(int level = 0) const;
DirectoryNode* advanceToMP3(const String songName);
DirectoryNode* advanceToNextMP3(const String currentGlobal);
DirectoryNode* advanceToMP3(const String& songName);
DirectoryNode* advanceToNextMP3(const String& currentGlobal);
DirectoryNode* goToPreviousMP3(uint32_t thresholdSeconds = 3);
DirectoryNode* findPreviousMP3Globally(const String currentGlobal);
DirectoryNode* findPreviousMP3Globally(const String& currentGlobal);
void buildFlatMP3List(std::vector<std::pair<DirectoryNode*, int>>& allMP3s);
DirectoryNode* advanceToMP3(const uint16_t id);
void advanceToFirstMP3InThisNode();