3 #include "AudioLogger.h"
4 #include "AudioTools/CoreAudio/AudioSource.h"
5 #include "AudioTools/CoreAudio/AudioBasic/Str.h"
16 #define SPI_CLOCK SD_SCK_MHZ(50)
18 #define MAX_FILE_LEN 256
20 #if defined(ARDUINO_ARCH_RP2040) && !defined(PICO)
22 typedef sdfat::SdSpiConfig SdSpiConfig;
23 typedef sdfat::SdFs AudioFs;
26 typedef SdFat AudioFs;
27 typedef File AudioFile;
28 #elif SD_FAT_TYPE == 1
29 typedef SdFat32 AudioFs;
30 typedef File32 AudioFile;
31 #elif SD_FAT_TYPE == 2
32 typedef SdExFat AudioFs;
33 typedef ExFile AudioFile;
34 #elif SD_FAT_TYPE == 3
36 typedef FsFile AudioFile;
48 class AudioSourceSDFAT :
public AudioSource {
51 AudioSourceSDFAT(
const char* startFilePath =
"/",
const char* ext =
".mp3",
int chipSelect = PIN_CS,
int speedMHz = 10) {
53 LOGI(
"SD chipSelect: %d", chipSelect);
54 LOGI(
"SD speedMHz: %d", speedMHz);
56 p_cfg =
new SdSpiConfig(chipSelect, DEDICATED_SPI, SD_SCK_MHZ(speedMHz));
58 start_path = startFilePath;
67 start_path = startFilePath;
74 if (p_cfg!=
nullptr && owns_cfg){
81 static bool is_sd_setup =
false;
83 while (!sd.begin(*p_cfg)) {
84 LOGE(
"SD.begin failed with cs=%d!", p_cfg->csPin);
85 sd.initErrorHalt(&Serial);
94 LOGW(
"-> nextStream: %d", offset);
102 file.getName(file_name, MAX_FILE_LEN);
103 LOGW(
"-> selectStream: %d '%s'", idx_pos, file_name);
104 return file ? &file :
nullptr;
109 file = getFileByPath(path);
110 LOGW(
"-> selectStream: %s", path);
111 return file ? &file :
nullptr;
116 file_name_pattern = (
char*)filter;
145 SdSpiConfig *p_cfg =
nullptr;
149 char file_name[MAX_FILE_LEN];
150 const char* exension =
nullptr;
151 const char* start_path =
nullptr;
152 char* file_name_pattern = (
char*)
"*";
158 LOGD(
"-> isValidAudioFile: '%s': %d", file_name,
false);
161 char file_name[MAX_FILE_LEN];
162 file.getName(file_name, MAX_FILE_LEN);
163 StrView strFileName(file_name);
165 LOGD(
"-> isValidAudioFile: '%s': %d", file_name, result);
169 AudioFile getFileByPath(
const char* path) {
176 strfileName.
substring(path, pos, inPath.length());
177 if (!dir.open(strPath.
c_str())) {
178 LOGE(
"directory: %s not open", path);
181 LOGE(
"directory: %s is not dictory", path);
183 if (!file.open(&dir, strfileName.
c_str(), O_RDWR)) {
184 LOGE(
"file: %s not open", path);
186 LOGD(
"-> getFileByPath: %s , %s", strPath.
c_str(), strfileName.
c_str());
198 if (sd.exists(dirStr)){
199 LOGI(
"directory: '%s'", dirStr);
200 if (dir.open(dirStr)){
203 getFileAtIndex(dir, pos, count, result);
204 result.getName(file_name, MAX_FILE_LEN);
205 result.setTimeout(timeout);
206 LOGI(
"-> getFile: '%s': %d - %s", file_name, pos, result.isOpen() ?
"open":
"closed");
208 LOGE(
"'%s' is not a directory!", dirStr);
211 LOGE(
"Could not open direcotry: '%s'", dirStr);
214 LOGE(
"directory: '%s' does not exist", dirStr);
221 void getFileAtIndex(AudioFile dir,
size_t pos,
size_t& idx, AudioFile& result) {
222 LOGD(
"%s: %d", LOG_METHOD, idx);
223 char file_name_act[MAX_FILE_LEN];
224 dir.getName(file_name_act, MAX_FILE_LEN);
225 LOGD(
"-> processing directory: %s ", file_name_act);
228 while (!result && file.openNext(&dir, O_RDONLY)) {
230 if (!file.isHidden()) {
231 file.getName(file_name_act, MAX_FILE_LEN);
232 LOGD(
"-> processing: %s with index %d", file_name_act, idx);
237 result.getName(file_name, MAX_FILE_LEN);
238 LOGD(
"==> found: '%s' at index %d", file_name, idx);
244 getFileAtIndex(file, pos, idx, result);
248 if (file.dirIndex()!=result.dirIndex()){
249 LOGD(
"Close: %s", file_name_act);