arduino-audio-tools
All Classes Namespaces Files Functions Variables Typedefs Enumerations Friends Modules Pages
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
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 void 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 }
92
93 virtual Stream* nextStream(int offset) override {
94 LOGW("-> nextStream: %d", offset);
95 return selectStream(idx_pos+offset);
96 }
97
98 virtual Stream* selectStream(int index) override {
99 idx_pos = index<0 ? 0 : index;
100 file.close();
101 file = getFileByPos(start_path, idx_pos);
102 file.getName(file_name, MAX_FILE_LEN);
103 LOGW("-> selectStream: %d '%s'", idx_pos, file_name);
104 return file ? &file : nullptr;
105 }
106
107 virtual Stream* selectStream(const char* path) override {
108 file.close();
109 file = getFileByPath(path);
110 LOGW("-> selectStream: %s", path);
111 return file ? &file : nullptr;
112 }
113
115 void setFileFilter(const char* filter) {
116 file_name_pattern = (char*)filter;
117 }
118
120 int index() {
121 return idx_pos;
122 }
123
125 const char *toStr() {
126 return file_name;
127 }
128
129 // provides default setting go to the next
130 virtual bool isAutoNext() {
131 return true;
132 };
133
135 virtual void setPath(const char* p) {
136 start_path = p;
137 }
138
139 virtual void setTimeout(int ms){
140 timeout = ms;
141 }
142
143protected:
144 AudioFile file;
145 SdSpiConfig *p_cfg = nullptr;
146 bool owns_cfg=false;
147 AudioFs sd;
148 size_t idx_pos = 0;
149 char file_name[MAX_FILE_LEN];
150 const char* exension = nullptr;
151 const char* start_path = nullptr;
152 char* file_name_pattern = (char*) "*";
153 int timeout;
154
156 bool isValidAudioFile(AudioFile& file) {
157 if (file.isDir()){
158 LOGD("-> isValidAudioFile: '%s': %d", file_name, false);
159 return false;
160 }
161 char file_name[MAX_FILE_LEN];
162 file.getName(file_name, MAX_FILE_LEN);
163 StrView strFileName(file_name);
164 bool result = strFileName.endsWithIgnoreCase(exension) && strFileName.matches(file_name_pattern);
165 LOGD("-> isValidAudioFile: '%s': %d", file_name, result);
166 return result;
167 }
168
169 AudioFile getFileByPath(const char* path) {
170 AudioFile dir;
171 StrView inPath(path);
172 Str strPath;
174 int pos = inPath.lastIndexOf("/") + 1;
175 strPath.substring(path, 0, pos);
176 strfileName.substring(path, pos, inPath.length());
177 if (!dir.open(strPath.c_str())) {
178 LOGE("directory: %s not open", path);
179 } else {
180 if (!dir.isDir()) {
181 LOGE("directory: %s is not dictory", path);
182 } else {
183 if (!file.open(&dir, strfileName.c_str(), O_RDWR)) {
184 LOGE("file: %s not open", path);
185 } else{
186 LOGD("-> getFileByPath: %s , %s", strPath.c_str(), strfileName.c_str());
187 }
188 }
189 }
190 dir.close();
191 return file;
192 }
193
195 AudioFile getFileByPos(const char* dirStr, int pos) {
196 AudioFile dir;
197 AudioFile result;
198 if (sd.exists(dirStr)){
199 LOGI("directory: '%s'", dirStr);
200 if (dir.open(dirStr)){
201 if (dir.isDir()) {
202 size_t count = 0;
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");
207 } else {
208 LOGE("'%s' is not a directory!", dirStr);
209 }
210 } else {
211 LOGE("Could not open direcotry: '%s'", dirStr);
212 }
213 } else {
214 LOGE("directory: '%s' does not exist", dirStr);
215 }
216 dir.close();
217
218 return result;
219 }
220
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);
226 AudioFile file;
227 dir.rewind();
228 while (!result && file.openNext(&dir, O_RDONLY)) {
229 // indent for dir level
230 if (!file.isHidden()) {
231 file.getName(file_name_act, MAX_FILE_LEN);
232 LOGD("-> processing: %s with index %d", file_name_act, idx);
233
234 if (isValidAudioFile(file)){
235 if (idx == pos) {
236 result = file;
237 result.getName(file_name, MAX_FILE_LEN);
238 LOGD("==> found: '%s' at index %d", file_name, idx);
239 }
240 idx++;
241 }
242
243 if (file.isDir()) {
244 getFileAtIndex(file, pos, idx, result);
245 }
246 }
247
248 if (file.dirIndex()!=result.dirIndex()){
249 LOGD("Close: %s", file_name_act);
250 file.close();
251 }
252 }
253 return;
254 }
255};
256
257}
Abstract Audio Data Source for the AudioPlayer which is used by the Audio Players.
Definition AudioSource.h:14
AudioSource for AudioPlayer using an SD card as data source. This class is based on https://github....
Definition LegacyAudioSourceSDFAT.h:48
int index()
Provides the current index position.
Definition LegacyAudioSourceSDFAT.h:120
AudioFile getFileByPos(const char *dirStr, int pos)
Determines the file at the indicated index (starting with 0)
Definition LegacyAudioSourceSDFAT.h:195
virtual Stream * selectStream(int index) override
Returns audio stream at the indicated index (the index is zero based, so the first value is 0!...
Definition LegacyAudioSourceSDFAT.h:98
virtual void setTimeout(int ms)
Sets the timeout of Stream in milliseconds.
Definition LegacyAudioSourceSDFAT.h:139
AudioSourceSDFAT(const char *startFilePath="/", const char *ext=".mp3", int chipSelect=PIN_CS, int speedMHz=10)
Default constructor.
Definition LegacyAudioSourceSDFAT.h:51
virtual void begin() override
Reset actual stream and move to root.
Definition LegacyAudioSourceSDFAT.h:79
const char * toStr()
provides the actual file name
Definition LegacyAudioSourceSDFAT.h:125
virtual void setPath(const char *p)
Allows to "correct" the start path if not defined in the constructor.
Definition LegacyAudioSourceSDFAT.h:135
virtual ~AudioSourceSDFAT()
Destructor.
Definition LegacyAudioSourceSDFAT.h:72
bool isValidAudioFile(AudioFile &file)
checks if the file is a valid audio file
Definition LegacyAudioSourceSDFAT.h:156
virtual Stream * nextStream(int offset) override
Returns next audio stream.
Definition LegacyAudioSourceSDFAT.h:93
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:130
void setFileFilter(const char *filter)
Defines the regex filter criteria for selecting files. E.g. ".*Bob Dylan.*".
Definition LegacyAudioSourceSDFAT.h:115
virtual Stream * selectStream(const char *path) override
Returns audio stream by path.
Definition LegacyAudioSourceSDFAT.h:107
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 const char * c_str()
provides the string value as const char*
Definition StrView.h:379
Definition NoArduino.h:142
Vector implementation which provides the most important methods as defined by std::vector....
Definition Vector.h:21
Generic Implementation of sound input and output for desktop environments using portaudio.
Definition AudioConfig.h:885