diff --git a/src/AudioLibs/AudioSourceIdxSDFAT.h b/src/AudioLibs/AudioSourceIdxSDFAT.h index c15187a69e..0d259c90c3 100644 --- a/src/AudioLibs/AudioSourceIdxSDFAT.h +++ b/src/AudioLibs/AudioSourceIdxSDFAT.h @@ -1,17 +1,16 @@ #pragma once -#include "AudioConfig.h" - #include #include -#include "AudioLogger.h" + #include "AudioBasic/StrExt.h" +#include "AudioConfig.h" +#include "AudioLogger.h" #include "AudioTools/AudioSource.h" #define USE_SDFAT #include "AudioLibs/SDIndex.h" - // SD_FAT_TYPE = 0 for SdFat/File as defined in SdFatConfig.h, // 1 for FAT16/FAT32, 2 for exFAT, 3 for FAT16/FAT32 and exFAT. #ifndef SD_FAT_TYPE @@ -20,20 +19,19 @@ // Try max SPI clock for an SD. Reduce SPI_CLOCK if errors occur. (40?) #define SPI_CLOCK SD_SCK_MHZ(50) #if SD_FAT_TYPE == 0 - typedef SdFat AudioFs; - typedef File AudioFile; +typedef SdFat AudioFs; +typedef File AudioFile; #elif SD_FAT_TYPE == 1 - typedef SdFat32 AudioFs; - typedef File32 AudioFile; +typedef SdFat32 AudioFs; +typedef File32 AudioFile; #elif SD_FAT_TYPE == 2 - typedef SdExFat AudioFs; - typedef ExFile AudioFile; +typedef SdExFat AudioFs; +typedef ExFile AudioFile; #elif SD_FAT_TYPE == 3 - typedef SdFs AudioFs; - typedef FsFile AudioFile; +typedef SdFs AudioFs; +typedef FsFile AudioFile; #endif - namespace audio_tools { /** * @brief ESP32 AudioSource for AudioPlayer using an SD card as data source. @@ -44,36 +42,38 @@ namespace audio_tools { * @copyright GPLv3 */ class AudioSourceIdxSDFAT : public AudioSource { -public: + public: /// Default constructor - AudioSourceIdxSDFAT(const char* startFilePath = "/", const char* ext = ".mp3", int chipSelect = PIN_CS, int speedMHz = 10, bool setupIndex=true) { - TRACED(); - LOGI("SD chipSelect: %d", chipSelect); - LOGI("SD speedMHz: %d", speedMHz); - LOGI("ext: %s", ext); - p_cfg = new SdSpiConfig(chipSelect, DEDICATED_SPI, SD_SCK_MHZ(speedMHz)); - owns_cfg = true; - start_path = startFilePath; - exension = ext; - setup_index = setupIndex; + AudioSourceIdxSDFAT(const char *startFilePath = "/", const char *ext = ".mp3", + int chipSelect = PIN_CS, int speedMHz = 10, + bool setupIndex = true) { + TRACED(); + LOGI("SD chipSelect: %d", chipSelect); + LOGI("SD speedMHz: %d", speedMHz); + LOGI("ext: %s", ext); + p_cfg = new SdSpiConfig(chipSelect, DEDICATED_SPI, SD_SCK_MHZ(speedMHz)); + owns_cfg = true; + start_path = startFilePath; + exension = ext; + setup_index = setupIndex; } - /// Costructor with SdSpiConfig - AudioSourceSDFAT(const char* startFilePath, const char* ext, SdSpiConfig &config, bool setupIndex=true) { - TRACED(); - p_cfg = &config; - owns_cfg = false; - start_path = startFilePath; - exension = ext; - setup_index = setupIndex; + /// Costructor with SdSpiConfig + AudioSourceIdxSDFAT(const char *startFilePath, const char *ext, + SdSpiConfig &config, bool setupIndex = true) { + TRACED(); + p_cfg = &config; + owns_cfg = false; + start_path = startFilePath; + exension = ext; + setup_index = setupIndex; } - virtual void begin() override { TRACED(); if (!is_sd_setup) { - if (!sd.begin(*p_cfg)) { - LOGE("sd.begin failed"); + if (!sd.begin(*p_cfg)) { + LOGE("sd.begin failed"); return; } is_sd_setup = true; @@ -83,9 +83,9 @@ class AudioSourceIdxSDFAT : public AudioSource { } void end() { - #ifdef ESP32 +#ifdef ESP32 sd.end(); - #endif +#endif is_sd_setup = false; } @@ -102,18 +102,18 @@ class AudioSourceIdxSDFAT : public AudioSource { virtual Stream *selectStream(const char *path) override { file.close(); - if (path==nullptr){ + if (path == nullptr) { LOGE("Filename is null") return nullptr; } - AudioFile new_file; - if (!new_file.open(path, O_RDONLY)){ + // AudioFile new_file; + if (!file.open(path, O_RDONLY)) { LOGE("Open error: '%s'", path); } LOGI("-> selectStream: %s", path); - file = new_file; + // file = new_file; return &file; } @@ -134,13 +134,13 @@ class AudioSourceIdxSDFAT : public AudioSource { virtual void setPath(const char *p) { start_path = p; } /// Provides the number of files (The max index is size()-1) - long size() { return idx.size();} + long size() { return idx.size(); } -protected: + protected: SdSpiConfig *p_cfg = nullptr; AudioFs sd; AudioFile file; - SDIndex idx{sd}; + SDIndex idx{sd}; size_t idx_pos = 0; char file_name[MAX_FILE_LEN]; const char *exension = nullptr; @@ -149,14 +149,13 @@ class AudioSourceIdxSDFAT : public AudioSource { bool setup_index = true; bool is_sd_setup = false; int cs; - bool owns_cfg=false; + bool owns_cfg = false; - const char* getFileName(AudioFile&file){ - static char name[MAX_FILE_LEN]; - file.getName(name,MAX_FILE_LEN); - return name; + const char *getFileName(AudioFile &file) { + static char name[MAX_FILE_LEN]; + file.getName(name, MAX_FILE_LEN); + return name; } - }; -} // namespace audio_tools \ No newline at end of file +} // namespace audio_tools \ No newline at end of file diff --git a/src/AudioLibs/AudioSourceSDFAT.h b/src/AudioLibs/AudioSourceSDFAT.h index aae67ad6cc..e578472a4b 100644 --- a/src/AudioLibs/AudioSourceSDFAT.h +++ b/src/AudioLibs/AudioSourceSDFAT.h @@ -1,17 +1,16 @@ #pragma once -#include "AudioConfig.h" - #include #include + #include "AudioBasic/StrExt.h" +#include "AudioConfig.h" #include "AudioLogger.h" #include "AudioTools/AudioSource.h" #define USE_SDFAT #include "AudioLibs/SDDirect.h" - // SD_FAT_TYPE = 0 for SdFat/File as defined in SdFatConfig.h, // 1 for FAT16/FAT32, 2 for exFAT, 3 for FAT16/FAT32 and exFAT. #ifndef SD_FAT_TYPE @@ -21,61 +20,62 @@ #define SPI_CLOCK SD_SCK_MHZ(50) #if SD_FAT_TYPE == 0 - typedef SdFat AudioFs; - typedef File AudioFile; +typedef SdFat AudioFs; +typedef File AudioFile; #elif SD_FAT_TYPE == 1 - typedef SdFat32 AudioFs; - typedef File32 AudioFile; +typedef SdFat32 AudioFs; +typedef File32 AudioFile; #elif SD_FAT_TYPE == 2 - typedef SdExFat AudioFs; - typedef ExFile AudioFile; +typedef SdExFat AudioFs; +typedef ExFile AudioFile; #elif SD_FAT_TYPE == 3 - typedef SdFs AudioFs; - typedef FsFile AudioFile; +typedef SdFs AudioFs; +typedef FsFile AudioFile; #endif - namespace audio_tools { /** * @brief ESP32 AudioSource for AudioPlayer using an SD card as data source. * This class is based on the Arduino SD implementation - * Connect the SD card. + * Connect the SD card. * For UTF8 Support change SdFatConfig.h #define USE_UTF8_LONG_NAMES 1 * @ingroup player * @author Phil Schatzmann * @copyright GPLv3 */ class AudioSourceSDFAT : public AudioSource { -public: + public: /// Default constructor - AudioSourceSDFAT(const char* startFilePath = "/", const char* ext = ".mp3", int chipSelect = PIN_CS, int speedMHz = 10,int spi_mode=DEDICATED_SPI, bool setupIndex=true) { - TRACED(); - LOGI("SD chipSelect: %d", chipSelect); - LOGI("SD speedMHz: %d", speedMHz); - LOGI("ext: %s", ext); - p_cfg = new SdSpiConfig(chipSelect, spi_mode, SD_SCK_MHZ(speedMHz)); - owns_cfg = true; - start_path = startFilePath; - exension = ext; - setup_index = setupIndex; + AudioSourceSDFAT(const char *startFilePath = "/", const char *ext = ".mp3", + int chipSelect = PIN_CS, int speedMHz = 10, + int spi_mode = DEDICATED_SPI, bool setupIndex = true) { + TRACED(); + LOGI("SD chipSelect: %d", chipSelect); + LOGI("SD speedMHz: %d", speedMHz); + LOGI("ext: %s", ext); + p_cfg = new SdSpiConfig(chipSelect, spi_mode, SD_SCK_MHZ(speedMHz)); + owns_cfg = true; + start_path = startFilePath; + exension = ext; + setup_index = setupIndex; } - /// Costructor with SdSpiConfig - AudioSourceSDFAT(const char* startFilePath, const char* ext, SdSpiConfig &config, bool setupIndex=true) { - TRACED(); - p_cfg = &config; - owns_cfg = false; - start_path = startFilePath; - exension = ext; - setup_index = setupIndex; + /// Costructor with SdSpiConfig + AudioSourceSDFAT(const char *startFilePath, const char *ext, + SdSpiConfig &config, bool setupIndex = true) { + TRACED(); + p_cfg = &config; + owns_cfg = false; + start_path = startFilePath; + exension = ext; + setup_index = setupIndex; } - virtual void begin() override { TRACED(); if (!is_sd_setup) { - if (!sd.begin(*p_cfg)) { - LOGE("sd.begin failed"); + if (!sd.begin(*p_cfg)) { + LOGE("sd.begin failed"); return; } is_sd_setup = true; @@ -91,7 +91,6 @@ class AudioSourceSDFAT : public AudioSource { is_sd_setup = false; } - virtual Stream *nextStream(int offset = 1) override { LOGI("nextStream: %d", offset); return selectStream(idx_pos + offset); @@ -99,7 +98,7 @@ class AudioSourceSDFAT : public AudioSource { virtual Stream *selectStream(int index) override { LOGI("selectStream SDFAT: %d", index); - if(index > -1){ //avoid invalid position + if (index > -1) { // avoid invalid position idx_pos = index; } return selectStream(idx[idx_pos]); @@ -107,19 +106,19 @@ class AudioSourceSDFAT : public AudioSource { virtual Stream *selectStream(const char *path) override { file.close(); - if (path==nullptr){ + if (path == nullptr) { LOGE("Filename is null") return nullptr; } - AudioFile new_file; - if (!new_file.open(path, O_RDONLY)){ - LOGE("Open error: '%s'", path); + // AudioFile new_file; + if (!file.open(path, O_RDONLY)) { + LOGE("Open error: '%s'", path); } LOGI("-> selectStream: %s", path); strncpy(file_name, path, MAX_FILE_LEN); - file = new_file; + // file = new_file; return &file; } @@ -139,14 +138,15 @@ class AudioSourceSDFAT : public AudioSource { /// Allows to "correct" the start path if not defined in the constructor virtual void setPath(const char *p) { start_path = p; } - /// Provides the number of files (The max index is size()-1): WARNING this is very slow if you have a lot of files in many subdirectories - long size() { return idx.size();} + /// Provides the number of files (The max index is size()-1): WARNING this is + /// very slow if you have a lot of files in many subdirectories + long size() { return idx.size(); } -protected: + protected: SdSpiConfig *p_cfg = nullptr; AudioFs sd; AudioFile file; - SDDirect idx{sd}; + SDDirect idx{sd}; size_t idx_pos = 0; char file_name[MAX_FILE_LEN]; const char *exension = nullptr; @@ -154,15 +154,14 @@ class AudioSourceSDFAT : public AudioSource { const char *file_name_pattern = "*"; int cs; bool setup_index = true; - bool owns_cfg=false; + bool owns_cfg = false; bool is_sd_setup = false; - const char* getFileName(AudioFile&file){ - static char name[MAX_FILE_LEN]; - file.getName(name,MAX_FILE_LEN); - return name; + const char *getFileName(AudioFile &file) { + static char name[MAX_FILE_LEN]; + file.getName(name, MAX_FILE_LEN); + return name; } - }; -} // namespace audio_tools +} // namespace audio_tools diff --git a/src/AudioLibs/SDDirect.h b/src/AudioLibs/SDDirect.h index 4a236a0f09..2f74652592 100644 --- a/src/AudioLibs/SDDirect.h +++ b/src/AudioLibs/SDDirect.h @@ -10,251 +10,244 @@ namespace audio_tools { /** - * @brief We access the files directy with an index. The index is determined by a recurseve - * tree walk thru the directory. Unfortunatly the SDTFAT library has it's own API which is - * incompatible with the SDT API + * @brief We access the files directy with an index. The index is determined by + * a recurseve tree walk thru the directory. Unfortunatly the SDTFAT library has + * it's own API which is incompatible with the SDT API */ -template +template class SDDirect { - public: - SDDirect(SDT &sd) { - p_sd = &sd; - }; - - void begin(const char *startDir, const char *extension, - const char *file_name_pattern) { - TRACED(); - this->start_dir = startDir; - this->ext = extension; - this->file_name_pattern = file_name_pattern; - this->max_idx = -1; - } + public: + SDDirect(SDT &sd) { p_sd = &sd; }; + + void begin(const char *startDir, const char *extension, + const char *file_name_pattern) { + TRACED(); + this->start_dir = startDir; + this->ext = extension; + this->file_name_pattern = file_name_pattern; + this->max_idx = -1; + } + /// Access file name by index + const char *operator[](int idx) { + if (max_idx != -1 && idx > max_idx) { + return nullptr; + } - /// Access file name by index - const char *operator[](int idx) { - if (max_idx!=-1 && idx>max_idx){ - return nullptr; - } + requested_idx = idx; + actual_idx = -1; + found = false; + listDir(start_dir); + if (!found) return nullptr; + return result.c_str(); + } - requested_idx = idx; + /// Provides the number of files + long size() { + if (max_idx == -1) { + requested_idx = MAX_FILE_COUNT; actual_idx = -1; found = false; listDir(start_dir); - if (!found) return nullptr; - return result.c_str(); + max_idx = actual_idx; } + return max_idx; + } - /// Provides the number of files - long size() { - if (max_idx==-1){ - requested_idx = MAX_FILE_COUNT; - actual_idx = -1; - found = false; - listDir(start_dir); - max_idx = actual_idx; - } - return max_idx; + protected: + String result; + const char *start_dir; + SDT *p_sd = nullptr; + int32_t actual_idx; + size_t requested_idx; + long max_idx = -1; + bool found = false; + List file_path_stack; + String file_path_str; + + const char *ext = nullptr; + const char *file_name_pattern = nullptr; + + /// Writes the index file + void listDir(const char *dirname) { + if (dirname == nullptr) return; + LOGD("listDir: %s", dirname); + FileT root = open(dirname); + if (!root) { + LOGE("Open failed: %s", dirname); + popPath(); + return; } - - protected: - String result; - const char* start_dir; - SDT *p_sd = nullptr; - int32_t actual_idx; - size_t requested_idx; - long max_idx=-1; - bool found = false; - List file_path_stack; - String file_path_str; - - const char *ext = nullptr; - const char *file_name_pattern = nullptr; - - /// Writes the index file - void listDir(const char *dirname) { - if (dirname==nullptr) return; - LOGD("listDir: %s", dirname); - FileT root = open(dirname); - if (!root) { - LOGE("Open failed: %s", dirname); - popPath(); - return; - } - if (!isDirectory(root)) { - LOGD("Is not directory: %s", dirname); - popPath(); - return; - } - if (Str(dirname).startsWith(".")) { - LOGD("Invalid file: %s", dirname); - popPath(); - return; - } - if (isDirectory(root)){ - rewind(root); - } - found = false; - FileT file = openNext(root); - while (file && !found) { - if (isDirectory(file)) { - String name = String(fileNamePath(file)); - LOGD("name: %s", name.c_str()); - pushPath(fileName(file)); - // recurseve call to get all files of this directory - listDir(name.c_str()); - } else { - const char* fn = fileNamePath(file); - if (isValidAudioFile(file)) { - actual_idx++; - LOGD("File %s at index: %d", fn, actual_idx); - if (actual_idx==requested_idx){ - result = String(fn); - found = true; - } - } else { - LOGD("Ignoring %s",fn); + if (!isDirectory(root)) { + LOGD("Is not directory: %s", dirname); + popPath(); + return; + } + if (Str(dirname).startsWith(".")) { + LOGD("Invalid file: %s", dirname); + popPath(); + return; + } + if (isDirectory(root)) { + rewind(root); + } + found = false; + FileT file = openNext(root); + while (file && !found) { + if (isDirectory(file)) { + String name = String(fileNamePath(file)); + LOGD("name: %s", name.c_str()); + pushPath(fileName(file)); + // recurseve call to get all files of this directory + listDir(name.c_str()); + } else { + const char *fn = fileNamePath(file); + if (isValidAudioFile(file)) { + actual_idx++; + LOGD("File %s at index: %d", fn, actual_idx); + if (actual_idx == requested_idx) { + result = String(fn); + found = true; } + } else { + LOGD("Ignoring %s", fn); } - file = openNext(root); - } - // stop processing and record maximum index - if (!found && file_path_stack.size()==0){ - max_idx = actual_idx; } - popPath(); + file = openNext(root); + } + // stop processing and record maximum index + if (!found && file_path_stack.size() == 0) { + max_idx = actual_idx; } + popPath(); + } - void rewind(FileT f){ - TRACED(); + void rewind(FileT &f) { + TRACED(); #ifdef USE_SDFAT - f.rewind(); + f.rewind(); #else - f.rewindDirectory(); + f.rewindDirectory(); #endif - } + } - bool isDirectory(FileT f) { - bool result; + bool isDirectory(FileT &f) { + bool result; #ifdef USE_SDFAT - result = f.isDir(); + result = f.isDir(); #else - result = f.isDirectory(); + result = f.isDirectory(); #endif - LOGD("isDirectory %s: %d", fileName(f), result); - return result; - } + LOGD("isDirectory %s: %d", fileName(f), result); + return result; + } - FileT openNext(FileT &dir) { - TRACED(); + FileT openNext(FileT &dir) { + TRACED(); #ifdef USE_SDFAT - FileT result; - if (!result.openNext(&dir, O_READ)){ - LOGD("No next file"); - } - return result; + FileT result; + if (!result.openNext(&dir, O_READ)) { + LOGD("No next file"); + } + return result; #else - return dir.openNextFile(); + return dir.openNextFile(); #endif - } + } - void pushPath(const char* name){ - TRACED(); - LOGD("pushPath: %s", name); - String nameStr(name); - file_path_stack.push_back(nameStr); - } + void pushPath(const char *name) { + TRACED(); + LOGD("pushPath: %s", name); + String nameStr(name); + file_path_stack.push_back(nameStr); + } - void popPath(){ - TRACED(); - String str; - file_path_stack.pop_back(str); - LOGD("popPath: %s", str.c_str()); - } + void popPath() { + TRACED(); + String str; + file_path_stack.pop_back(str); + LOGD("popPath: %s", str.c_str()); + } - /// checks if the file is a valid audio file - bool isValidAudioFile(FileT &file) { - const char *file_name = fileName(file); - if (file.isDirectory()) { - LOGD("-> isValidAudioFile: '%s': %d", file_name, false); - return false; - } - Str strFileTName(file_name); - bool result = strFileTName.endsWithIgnoreCase(ext) - && strFileTName.matches(file_name_pattern) - && !isHidden(file); - LOGD("-> isValidAudioFile: '%s': %d", file_name, result); - return result; + /// checks if the file is a valid audio file + bool isValidAudioFile(FileT &file) { + const char *file_name = fileName(file); + if (file.isDirectory()) { + LOGD("-> isValidAudioFile: '%s': %d", file_name, false); + return false; } + Str strFileTName(file_name); + bool result = strFileTName.endsWithIgnoreCase(ext) && + strFileTName.matches(file_name_pattern) && !isHidden(file); + LOGD("-> isValidAudioFile: '%s': %d", file_name, result); + return result; + } - - /// Returns the filename w/o path - const char* fileName(FileT&file){ -#ifdef USE_SDFAT - // add name - static char name[MAX_FILE_LEN]; - file.getName(name,MAX_FILE_LEN); - return name; + /// Returns the filename w/o path + const char *fileName(FileT &file) { +#ifdef USE_SDFAT + // add name + static char name[MAX_FILE_LEN]; + file.getName(name, MAX_FILE_LEN); + return name; #else - Str tmp(file.name()); - int pos=0; - // remove directories - if (tmp.contains("/")){ - pos = tmp.lastIndexOf("/")+1; - } - return file.name()+pos; + Str tmp(file.name()); + int pos = 0; + // remove directories + if (tmp.contains("/")) { + pos = tmp.lastIndexOf("/") + 1; + } + return file.name() + pos; #endif } - /// Returns the filename including the path - const char* fileNamePath(FileT &file){ -#if defined(USE_SDFAT) || ESP_IDF_VERSION_MAJOR >= 4 - LOGD("-> fileNamePath: %s", fileName(file)); - file_path_str = start_dir; - if (!file_path_str.endsWith("/")){ - file_path_str += "/"; - } - for (int j=0; j= 4 + LOGD("-> fileNamePath: %s", fileName(file)); + file_path_str = start_dir; + if (!file_path_str.endsWith("/")) { + file_path_str += "/"; + } + for (int j = 0; j < file_path_stack.size(); j++) { + file_path_str += file_path_stack[j] + "/"; + } + // add name + static char name[MAX_FILE_LEN]; + strncpy(name, fileName(file), MAX_FILE_LEN); + file_path_str += name; + const char *result = file_path_str.c_str(); + LOGD("<- fileNamePath: %s", result); + return result; #else - return file.name(); + return file.name(); #endif - } + } - bool isHidden(FileT f){ + bool isHidden(FileT &f) { #ifdef USE_SDFAT - return f.isHidden(); + return f.isHidden(); #else - return Str(fileNamePath(f)).contains("/."); + return Str(fileNamePath(f)).contains("/."); #endif + } - } - - FileT open(const char* name){ - TRACED(); + FileT open(const char *name) { + TRACED(); #ifdef USE_SDFAT - FileT result; - if (!result.open(name)){ - if (name!=nullptr){ - LOGE("File open error: %s", name); - } else { - LOGE("File open error: name is null"); - } + FileT result; + if (!result.open(name)) { + if (name != nullptr) { + LOGE("File open error: %s", name); + } else { + LOGE("File open error: name is null"); } - return result; + } + return result; #else - return p_sd->open(name); + return p_sd->open(name); #endif - } - + } }; -} \ No newline at end of file +} // namespace audio_tools \ No newline at end of file diff --git a/src/AudioLibs/SDIndex.h b/src/AudioLibs/SDIndex.h index 307da32b25..2fd248f967 100644 --- a/src/AudioLibs/SDIndex.h +++ b/src/AudioLibs/SDIndex.h @@ -9,314 +9,308 @@ namespace audio_tools { - /** * @brief We store all the relevant file names in an sequential index * file. Form there we can access them via an index */ -template +template class SDIndex { - public: - SDIndex(SDT &sd) { - p_sd = &sd; - }; - void begin(const char *startDir, const char *extension, - const char *file_name_pattern, bool setupIndex=true) { - TRACED(); - this->start_dir = startDir; - this->ext = extension; - this->file_name_pattern = file_name_pattern; - idx_path = filePathString(startDir,"idx.txt"); - idx_defpath = filePathString(startDir,"idx-def.txt"); - int idx_file_size = indexFileTSize(); - LOGI("Index file size: %d", idx_file_size); - String keyNew = String(startDir) + "|" + extension + "|" + file_name_pattern; - String keyOld = getIndexDef(); - if (setupIndex && (keyNew != keyOld || idx_file_size==0)) { - FileT idxfile = p_sd->open(idx_path.c_str(), FILE_WRITE); - LOGW("Creating index file"); - listDir(idxfile, startDir); - LOGI("Indexing completed"); - idxfile.close(); - // update index definition file - saveIndexDef(keyNew); - } + public: + SDIndex(SDT &sd) { p_sd = &sd; }; + void begin(const char *startDir, const char *extension, + const char *file_name_pattern, bool setupIndex = true) { + TRACED(); + this->start_dir = startDir; + this->ext = extension; + this->file_name_pattern = file_name_pattern; + idx_path = filePathString(startDir, "idx.txt"); + idx_defpath = filePathString(startDir, "idx-def.txt"); + int idx_file_size = indexFileTSize(); + LOGI("Index file size: %d", idx_file_size); + String keyNew = + String(startDir) + "|" + extension + "|" + file_name_pattern; + String keyOld = getIndexDef(); + if (setupIndex && (keyNew != keyOld || idx_file_size == 0)) { + FileT idxfile = p_sd->open(idx_path.c_str(), FILE_WRITE); + LOGW("Creating index file"); + listDir(idxfile, startDir); + LOGI("Indexing completed"); + idxfile.close(); + // update index definition file + saveIndexDef(keyNew); } + } - void ls(Print &p, const char *startDir, const char *extension, - const char *file_name_pattern="*"){ - TRACED(); - this->ext = extension; - this->file_name_pattern = file_name_pattern; - listDir(p, startDir); - file_path_stack.clear(); - file_path_str.clear(); + void ls(Print &p, const char *startDir, const char *extension, + const char *file_name_pattern = "*") { + TRACED(); + this->ext = extension; + this->file_name_pattern = file_name_pattern; + listDir(p, startDir); + file_path_stack.clear(); + file_path_str.clear(); + } + /// Access file name by index + const char *operator[](int idx) { + // return null when inx too big + if (max_idx >= 0 && idx > max_idx) { + LOGE("idx %d > size %d", idx, max_idx); + return nullptr; } + // find record + FileT idxfile = p_sd->open(idx_path.c_str()); + int count = 0; - /// Access file name by index - const char *operator[](int idx) { - // return null when inx too big - if (max_idx>=0 && idx>max_idx) { - LOGE("idx %d > size %d", idx, max_idx); - return nullptr; + if (idxfile.available() == 0) { + LOGE("Index file is empty"); + } + + bool found = false; + while (idxfile.available() > 0 && !found) { + result = idxfile.readStringUntil('\n'); + + // result c-string + char *c_str = (char *)result.c_str(); + // remove potential cr character - hax to avoid any allocations + int lastPos = result.length() - 1; + if (c_str[lastPos] == 13) { + c_str[lastPos] = 0; } - // find record - FileT idxfile = p_sd->open(idx_path.c_str()); - int count=0; - if (idxfile.available()==0){ - LOGE("Index file is empty"); + LOGD("%d -> %s", count, c_str); + if (count == idx) { + found = true; } + count++; + } + if (!found) { + max_idx = count; + } + idxfile.close(); - bool found = false; - while (idxfile.available()>0 && !found) { - result = idxfile.readStringUntil('\n'); + return found ? result.c_str() : nullptr; + } + + long size() { + if (max_idx == -1) { + FileT idxfile = p_sd->open(idx_path.c_str()); + int count = 0; + while (idxfile.available() > 0) { + result = idxfile.readStringUntil('\n'); // result c-string - char *c_str = (char*)result.c_str(); - // remove potential cr character - hax to avoid any allocations - int lastPos = result.length()-1; - if (c_str[lastPos]==13){ - c_str[lastPos] = 0; - } - - LOGD("%d -> %s", count, c_str); - if (count==idx) { - found=true; - } + char *c_str = (char *)result.c_str(); count++; } - if (!found){ - max_idx = count; - } idxfile.close(); - - return found ? result.c_str(): nullptr; + max_idx = count; } + return max_idx; + } - long size() { - if (max_idx==-1){ - FileT idxfile = p_sd->open(idx_path.c_str()); - int count=0; + protected: + String result; + String idx_path; + String idx_defpath; + SDT *p_sd = nullptr; + List file_path_stack; + String file_path_str; + const char *start_dir; + + const char *ext = nullptr; + const char *file_name_pattern = nullptr; + long max_idx = -1; + + String filePathString(const char *name, const char *suffix) { + String result = name; + return result.endsWith("/") ? result + suffix : result + "/" + suffix; + } - while (idxfile.available()>0) { - result = idxfile.readStringUntil('\n'); - // result c-string - char *c_str = (char*)result.c_str(); - count++; - } - idxfile.close(); - max_idx = count; - } - return max_idx; + /// Writes the index file + void listDir(Print &idxfile, const char *dirname) { + LOGD("listDir: %s", dirname); + FileT root = open(dirname); + if (!root) { + LOGE("Open failed: %s", dirname); + popPath(); + return; } - - protected: - String result; - String idx_path; - String idx_defpath; - SDT *p_sd = nullptr; - List file_path_stack; - String file_path_str; - const char* start_dir; - - const char *ext = nullptr; - const char *file_name_pattern = nullptr; - long max_idx=-1; - - String filePathString(const char* name, const char* suffix){ - String result = name; - return result.endsWith("/") ? result+suffix: result+"/"+suffix; + if (!isDirectory(root)) { + LOGD("Is not directory: %s", dirname); + popPath(); + return; + } + if (Str(dirname).startsWith(".")) { + LOGD("Invalid file: %s", dirname); + popPath(); + return; } - /// Writes the index file - void listDir(Print &idxfile, const char *dirname) { - LOGD("listDir: %s", dirname); - FileT root = open(dirname); - if (!root) { - LOGE("Open failed: %s", dirname); - popPath(); - return; - } - if (!isDirectory(root)) { - LOGD("Is not directory: %s", dirname); - popPath(); - return; - } - if (Str(dirname).startsWith(".")) { - LOGD("Invalid file: %s", dirname); - popPath(); - return; - } - - rewind(root); - FileT file = openNext(root); - while (file) { - if (isDirectory(file)) { - String name = String(fileNamePath(file)); - LOGD("name: %s", name.c_str()); - pushPath(fileName(file)); - listDir(idxfile, name.c_str()); + rewind(root); + FileT file = openNext(root); + while (file) { + if (isDirectory(file)) { + String name = String(fileNamePath(file)); + LOGD("name: %s", name.c_str()); + pushPath(fileName(file)); + listDir(idxfile, name.c_str()); + } else { + const char *fn = fileNamePath(file); + if (isValidAudioFile(file)) { + LOGD("Adding file to index: %s", fn); + idxfile.println(fn); } else { - const char* fn = fileNamePath(file); - if (isValidAudioFile(file)) { - LOGD("Adding file to index: %s", fn); - idxfile.println(fn); - } else { - LOGD("Ignoring %s",fn); - } + LOGD("Ignoring %s", fn); } - file = openNext(root); } - popPath(); + file = openNext(root); } + popPath(); + } - bool isDirectory(FileT f) { - bool result; + bool isDirectory(FileT &f) { + bool result; #ifdef USE_SDFAT - result = f.isDir(); + result = f.isDir(); #else - result = f.isDirectory(); + result = f.isDirectory(); #endif - LOGD("isDirectory %s: %d", fileName(f), result); - return result; - } + LOGD("isDirectory %s: %d", fileName(f), result); + return result; + } - FileT openNext(FileT &dir) { - TRACED(); + FileT openNext(FileT &dir) { + TRACED(); #ifdef USE_SDFAT - FileT result; - if (!result.openNext(&dir, O_READ)){ - LOGD("No next file"); - } - return result; + FileT result; + if (!result.openNext(&dir, O_READ)) { + LOGD("No next file"); + } + return result; #else - return dir.openNextFile(); + return dir.openNextFile(); #endif - } + } - void pushPath(const char* name){ - LOGD("pushPath: %s", name); - LOGD("pushPath: %s", name); - String nameStr(name); - file_path_stack.push_back(nameStr); - } + void pushPath(const char *name) { + LOGD("pushPath: %s", name); + LOGD("pushPath: %s", name); + String nameStr(name); + file_path_stack.push_back(nameStr); + } - void popPath(){ - TRACED(); - String str; - file_path_stack.pop_back(str); - LOGD("popPath: %s", str.c_str()); - } + void popPath() { + TRACED(); + String str; + file_path_stack.pop_back(str); + LOGD("popPath: %s", str.c_str()); + } - /// checks if the file is a valid audio file - bool isValidAudioFile(FileT &file) { - TRACED(); - const char *file_name = fileName(file); - if (file.isDirectory()) { - LOGD("-> isValidAudioFile: '%s': %d", file_name, false); - return false; - } - Str strFileTName(file_name); - bool result = strFileTName.endsWithIgnoreCase(ext) - && strFileTName.matches(file_name_pattern) - && !isHidden(file); - LOGD("-> isValidAudioFile: '%s': %d", file_name, result); - return result; + /// checks if the file is a valid audio file + bool isValidAudioFile(FileT &file) { + TRACED(); + const char *file_name = fileName(file); + if (file.isDirectory()) { + LOGD("-> isValidAudioFile: '%s': %d", file_name, false); + return false; } + Str strFileTName(file_name); + bool result = strFileTName.endsWithIgnoreCase(ext) && + strFileTName.matches(file_name_pattern) && !isHidden(file); + LOGD("-> isValidAudioFile: '%s': %d", file_name, result); + return result; + } - String getIndexDef() { - FileT idxdef = p_sd->open(idx_defpath.c_str()); - String key1 = idxdef.readString(); - idxdef.close(); - return key1; - } - void saveIndexDef(String keyNew){ - FileT idxdef = p_sd->open(idx_defpath.c_str(), FILE_WRITE); - idxdef.write((const uint8_t *)keyNew.c_str(), keyNew.length()); - idxdef.close(); - } + String getIndexDef() { + FileT idxdef = p_sd->open(idx_defpath.c_str()); + String key1 = idxdef.readString(); + idxdef.close(); + return key1; + } + void saveIndexDef(String keyNew) { + FileT idxdef = p_sd->open(idx_defpath.c_str(), FILE_WRITE); + idxdef.write((const uint8_t *)keyNew.c_str(), keyNew.length()); + idxdef.close(); + } - size_t indexFileTSize() { - FileT idxfile = p_sd->open(idx_path.c_str()); - size_t result = idxfile.size(); - idxfile.close(); - return result; - } + size_t indexFileTSize() { + FileT idxfile = p_sd->open(idx_path.c_str()); + size_t result = idxfile.size(); + idxfile.close(); + return result; + } - void rewind(FileT f){ - TRACED(); + void rewind(FileT &f) { + TRACED(); #ifdef USE_SDFAT - f.rewind(); + f.rewind(); #else - f.rewindDirectory(); + f.rewindDirectory(); #endif - } + } - /// Returns the filename w/o the path - const char* fileName(FileT&file){ + /// Returns the filename w/o the path + const char *fileName(FileT &file) { #ifdef USE_SDFAT - // add name - static char name[MAX_FILE_LEN]; - file.getName(name,MAX_FILE_LEN); - return name; + // add name + static char name[MAX_FILE_LEN]; + file.getName(name, MAX_FILE_LEN); + return name; #else - Str tmp(file.name()); - int pos=0; - // remove directories - if (tmp.contains("/")){ - pos = tmp.lastIndexOf("/")+1; - } - return file.name()+pos; + Str tmp(file.name()); + int pos = 0; + // remove directories + if (tmp.contains("/")) { + pos = tmp.lastIndexOf("/") + 1; + } + return file.name() + pos; #endif } - /// Returns the filename including the path - const char* fileNamePath(FileT &file){ -#if defined(USE_SDFAT) || ESP_IDF_VERSION_MAJOR >= 4 - LOGD("-> fileNamePath: %s", fileName(file)); - file_path_str = start_dir; - if (!file_path_str.endsWith("/")){ - file_path_str += "/"; - } - for (int j=0; j= 4 + LOGD("-> fileNamePath: %s", fileName(file)); + file_path_str = start_dir; + if (!file_path_str.endsWith("/")) { + file_path_str += "/"; + } + for (int j = 0; j < file_path_stack.size(); j++) { + file_path_str += file_path_stack[j] + "/"; + } + // add name + static char name[MAX_FILE_LEN]; + strncpy(name, fileName(file), MAX_FILE_LEN); + file_path_str += name; + const char *result = file_path_str.c_str(); + LOGD("<- fileNamePath: %s", result); + return result; #else - return file.name(); + return file.name(); #endif - } + } - bool isHidden(FileT f){ + bool isHidden(FileT &f) { #ifdef USE_SDFAT - return f.isHidden(); + return f.isHidden(); #else - return Str(fileNamePath(f)).contains("/."); + return Str(fileNamePath(f)).contains("/."); #endif + } - } - - FileT open(const char* name){ - TRACED(); + FileT open(const char *name) { + TRACED(); #ifdef USE_SDFAT - FileT result; - if (!result.open(name)){ - LOGE("FileT open error: %s", name); - } - return result; + FileT result; + if (!result.open(name)) { + LOGE("FileT open error: %s", name); + } + return result; #else - return p_sd->open(name); + return p_sd->open(name); #endif - } - + } }; -} \ No newline at end of file +} // namespace audio_tools \ No newline at end of file