arduino-audio-tools
Loading...
Searching...
No Matches
LegacyAudioSourceSDFAT.h
1#pragma once
2
3#include "AudioLogger.h"
4#include "AudioTools/Disk/AudioSource.h"
5#include "AudioTools/CoreAudio/AudioBasic/Str.h"
6#include <SPI.h>
7#include <SdFat.h>
8namespace audio_tools {
9
10// SD_FAT_TYPE = 0 for SdFat/File as defined in SdFatConfig.h,
11// 1 for FAT16/FAT32, 2 for exFAT, 3 for FAT16/FAT32 and exFAT.
12#ifndef SD_FAT_TYPE
13#define SD_FAT_TYPE 1
14#endif
15// Try max SPI clock for an SD. Reduce SPI_CLOCK if errors occur. (40?)
16#define SPI_CLOCK SD_SCK_MHZ(50)
17// Max file name length including directory path
18#define MAX_FILE_LEN 256
19
20#if defined(ARDUINO_ARCH_RP2040) && !defined(PICO)
21 // only RP2040 from Earle Phil Hower is using the library with a sdfat namespace
22 typedef sdfat::SdSpiConfig SdSpiConfig;
23 typedef sdfat::SdFs AudioFs;
24#else
25#if SD_FAT_TYPE == 0
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
35 typedef SdFs AudioFs;
36 typedef FsFile AudioFile;
37#else // SD_FAT_TYPE
38#endif
39#endif
40
41
48class AudioSourceSDFAT : public AudioSource {
49public:
51 AudioSourceSDFAT(const char* startFilePath = "/", const char* ext = ".mp3", int chipSelect = PIN_CS, int speedMHz = 10) {
52 TRACED();
53 LOGI("SD chipSelect: %d", chipSelect);
54 LOGI("SD speedMHz: %d", speedMHz);
55 LOGI("ext: %s", ext);
56 p_cfg = new SdSpiConfig(chipSelect, DEDICATED_SPI, SD_SCK_MHZ(speedMHz));
57 owns_cfg = true;
58 start_path = startFilePath;
59 exension = ext;
60 }
61
63 AudioSourceSDFAT(const char* startFilePath, const char* ext, SdSpiConfig &config) {
64 TRACED();
65 p_cfg = &config;
66 owns_cfg = false;
67 start_path = startFilePath;
68 exension = ext;
69 }
70
73 TRACED();
74 if (p_cfg!=nullptr && owns_cfg){
75 delete p_cfg;
76 }
77 }
78
79 virtual bool begin() override {
80 TRACED();
81 static bool is_sd_setup = false;
82 if (!is_sd_setup){
83 while (!sd.begin(*p_cfg)) {
84 LOGE("SD.begin failed with cs=%d!", p_cfg->csPin);
85 sd.initErrorHalt(&Serial);
86 delay(500);
87 }
88 is_sd_setup = true;
89 }
90 idx_pos = 0;
91 return is_sd_setup;
92 }
93
94 virtual Stream* nextStream(int offset) override {
95 LOGW("-> nextStream: %d", offset);
96 return selectStream(idx_pos+offset);
97 }
98
99 virtual Stream* selectStream(int index) override {
100 idx_pos = index<0 ? 0 : index;
101 file.close();
102 file = getFileByPos(start_path, idx_pos);
103 file.getName(file_name, MAX_FILE_LEN);
104 LOGW("-> selectStream: %d '%s'", idx_pos, file_name);
105 return file ? &file : nullptr;
106 }
107
108 virtual Stream* selectStream(const char* path) override {
109 file.close();
110 file = getFileByPath(path);
111 LOGW("-> selectStream: %s", path);
112 return file ? &file : nullptr;
113 }
114
116 void setFileFilter(const char* filter) {
117 file_name_pattern = (char*)filter;
118 }
119
121 int index() {
122 return idx_pos;
123 }
124
126 const char *toStr() {
127 return file_name;
128 }
129
130 // provides default setting go to the next
131 virtual bool isAutoNext() {
132 return true;
133 };
134
136 virtual void setPath(const char* p) {
137 start_path = p;
138 }
139
140 virtual void setTimeout(int ms){
141 timeout = ms;
142 }
143
144protected:
145 AudioFile file;
146 SdSpiConfig *p_cfg = nullptr;
147 bool owns_cfg=false;
148 AudioFs sd;
149 size_t idx_pos = 0;
150 char file_name[MAX_FILE_LEN];
151 const char* exension = nullptr;
152 const char* start_path = nullptr;
153 char* file_name_pattern = (char*) "*";
154 int timeout;
155
157 bool isValidAudioFile(AudioFile& file) {
158 if (file.isDir()){
159 LOGD("-> isValidAudioFile: '%s': %d", file_name, false);
160 return false;
161 }
162 char file_name[MAX_FILE_LEN];
163 file.getName(file_name, MAX_FILE_LEN);
164 StrView strFileName(file_name);
165 bool result = strFileName.endsWithIgnoreCase(exension) && strFileName.matches(file_name_pattern);
166 LOGD("-> isValidAudioFile: '%s': %d", file_name, result);
167 return result;
168 }
169
170 AudioFile getFileByPath(const char* path) {
171 AudioFile dir;
172 StrView inPath(path);
173 Str strPath;
174 Str strfileName;
175 int pos = inPath.lastIndexOf("/") + 1;
176 strPath.substring(path, 0, pos);
177 strfileName.substring(path, pos, inPath.length());
178 if (!dir.open(strPath.c_str())) {
179 LOGE("directory: %s not open", path);
180 } else {
181 if (!dir.isDir()) {
182 LOGE("directory: %s is not dictory", path);
183 } else {
184 if (!file.open(&dir, strfileName.c_str(), O_RDWR)) {
185 LOGE("file: %s not open", path);
186 } else{
187 LOGD("-> getFileByPath: %s , %s", strPath.c_str(), strfileName.c_str());
188 }
189 }
190 }
191 dir.close();
192 return file;
193 }
194
196 AudioFile getFileByPos(const char* dirStr, int pos) {
197 AudioFile dir;
198 AudioFile result;
199 if (sd.exists(dirStr)){
200 LOGI("directory: '%s'", dirStr);
201 if (dir.open(dirStr)){
202 if (dir.isDir()) {
203 size_t count = 0;
204 getFileAtIndex(dir, pos, count, result);
205 result.getName(file_name, MAX_FILE_LEN);
206 result.setTimeout(timeout);
207 LOGI("-> getFile: '%s': %d - %s", file_name, pos, result.isOpen() ? "open":"closed");
208 } else {
209 LOGE("'%s' is not a directory!", dirStr);
210 }
211 } else {
212 LOGE("Could not open direcotry: '%s'", dirStr);
213 }
214 } else {
215 LOGE("directory: '%s' does not exist", dirStr);
216 }
217 dir.close();
218
219 return result;
220 }
221
222 void getFileAtIndex(AudioFile dir, size_t pos, size_t& idx, AudioFile& result) {
223 LOGD("%s: %d", LOG_METHOD, idx);
224 char file_name_act[MAX_FILE_LEN];
225 dir.getName(file_name_act, MAX_FILE_LEN);
226 LOGD("-> processing directory: %s ", file_name_act);
227 AudioFile file;
228 dir.rewind();
229 while (!result && file.openNext(&dir, O_RDONLY)) {
230 // indent for dir level
231 if (!file.isHidden()) {
232 file.getName(file_name_act, MAX_FILE_LEN);
233 LOGD("-> processing: %s with index %d", file_name_act, idx);
234
235 if (isValidAudioFile(file)){
236 if (idx == pos) {
237 result = file;
238 result.getName(file_name, MAX_FILE_LEN);
239 LOGD("==> found: '%s' at index %d", file_name, idx);
240 }
241 idx++;
242 }
243
244 if (file.isDir()) {
245 getFileAtIndex(file, pos, idx, result);
246 }
247 }
248
249 if (file.dirIndex()!=result.dirIndex()){
250 LOGD("Close: %s", file_name_act);
251 file.close();
252 }
253 }
254 return;
255 }
256};
257
258}
int index()
Provides the current index position.
Definition AudioSourceSDFAT.h:135
AudioFile getFileByPos(const char *dirStr, int pos)
Determines the file at the indicated index (starting with 0)
Definition LegacyAudioSourceSDFAT.h:196
virtual Stream * selectStream(int index) override
Definition AudioSourceSDFAT.h:104
virtual void setTimeout(int ms)
Sets the timeout of Stream in milliseconds.
Definition LegacyAudioSourceSDFAT.h:140
virtual bool begin() override
Reset actual stream and move to root.
Definition LegacyAudioSourceSDFAT.h:79
AudioSourceSDFAT(const char *startFilePath="/", const char *ext=".mp3", int chipSelect=PIN_CS, int speedMHz=10)
Default constructor.
Definition LegacyAudioSourceSDFAT.h:51
const char * toStr()
provides the actual file name
Definition LegacyAudioSourceSDFAT.h:126
virtual void setPath(const char *p)
Allows to "correct" the start path if not defined in the constructor.
Definition LegacyAudioSourceSDFAT.h:136
virtual ~AudioSourceSDFAT()
Destructor.
Definition LegacyAudioSourceSDFAT.h:72
bool isValidAudioFile(AudioFile &file)
checks if the file is a valid audio file
Definition LegacyAudioSourceSDFAT.h:157
virtual Stream * nextStream(int offset) override
Returns next audio stream.
Definition LegacyAudioSourceSDFAT.h:94
AudioSourceSDFAT(const char *startFilePath, const char *ext, SdSpiConfig &config)
Costructor with SdSpiConfig.
Definition LegacyAudioSourceSDFAT.h:63
virtual bool isAutoNext()
Returns default setting go to the next.
Definition LegacyAudioSourceSDFAT.h:131
void setFileFilter(const char *filter)
Defines the regex filter criteria for selecting files. E.g. ".*Bob Dylan.*".
Definition LegacyAudioSourceSDFAT.h:116
virtual Stream * selectStream(const char *path) override
Returns audio stream by path: The index is not changed!
Definition LegacyAudioSourceSDFAT.h:108
Str which keeps the data on the heap. We grow the allocated memory only if the copy source is not fit...
Definition Str.h:24
A simple wrapper to provide string functions on existing allocated char*. If the underlying char* is ...
Definition StrView.h:28
virtual int lastIndexOf(const char *cont)
provides the position of the last occurrence of the indicated substring
Definition StrView.h:297
virtual bool matches(const char *pattern)
Definition StrView.h:193
virtual void substring(StrView &from, int start, int end)
copies a substring into the current string
Definition StrView.h:477
virtual const char * c_str()
provides the string value as const char*
Definition StrView.h:379
virtual bool endsWithIgnoreCase(const char *str)
checks if the string ends with the indicated substring
Definition StrView.h:185
Definition NoArduino.h:142
Generic Implementation of sound input and output for desktop environments using portaudio.
Definition AudioCodecsBase.h:10