arduino-audio-tools
Loading...
Searching...
No Matches
AudioSource.h
Go to the documentation of this file.
1#pragma once
2#include "AudioToolsConfig.h"
6
7namespace audio_tools {
8
18 public:
20 virtual bool begin() = 0;
21
23 virtual Stream* nextStream(int offset) = 0;
24
26 virtual Stream* previousStream(int offset) { return nextStream(-offset); };
27
30 virtual Stream* selectStream(int index) {
31 LOGE("Not Supported!");
32 return nullptr;
33 }
34
36 virtual Stream* setIndex(int index) { return selectStream(index); }
37
39 virtual int index() { return -1; }
40
42 virtual Stream* selectStream(const char* path) = 0;
43
49
51 virtual int timeoutAutoNext() { return timeout_auto_next_value; }
52
53 // only the ICYStream supports this
54 virtual bool setMetadataCallback(void (*fn)(MetaDataType info,
55 const char* str, int len),
57 return false;
58 }
59
61 virtual void setTimeout(int millisec) {};
62
64 virtual bool isAutoNext() { return is_auto_next; }
65
66 // Prevent automatic move to the next stream
67 virtual void setAutoNext(bool flag) { is_auto_next = flag; }
68
70 Stream* operator[](int idx) { return setIndex(idx); }
71
73 virtual const char* toStr() { return nullptr; }
74
75 protected:
77 bool is_auto_next = true;
78};
79
87 public:
89
96
98 virtual bool begin() override {
99 TRACED();
100 if (onStartCallback != nullptr) onStartCallback();
101 return true;
102 };
103
106 virtual Stream* nextStream(int offset) override {
107 TRACED();
108 return nextStreamCallback == nullptr ? nullptr : nextStreamCallback(offset);
109 }
110
112 virtual Stream* selectStream(int index) override {
113 LOGI("selectStream: %d", index);
114 if (indexStreamCallback == nullptr) {
115 LOGI("setCallbackSelectStream not provided");
116 if (index > 0) {
117 begin();
118 return nextStream(index);
119 } else {
120 // nextStream(0) will return the directory but we need a file
121 return nextStream(1);
122 }
123 }
125 }
127 virtual Stream* selectStream(const char* path) override {
128 this->path = path;
129 return indexStreamCallback == nullptr ? nullptr : indexStreamCallback(-1);
130 };
131
132 void setCallbackOnStart(void (*callback)()) { onStartCallback = callback; }
133
134 void setCallbackNextStream(Stream* (*callback)(int offset)) {
135 nextStreamCallback = callback;
136 }
137
138 void setCallbackSelectStream(Stream* (*callback)(int idx)) {
139 indexStreamCallback = callback;
140 }
141
142 virtual bool isAutoNext() override { return auto_next; }
143
144 virtual void setAutoNext(bool a) { auto_next = a; }
145
147 virtual const char* getPath() { return path; }
148
149 protected:
150 void (*onStartCallback)() = nullptr;
151 bool auto_next = true;
152 Stream* (*nextStreamCallback)(int offset) = nullptr;
153 Stream* (*indexStreamCallback)(int index) = nullptr;
154 const char* path = nullptr;
155};
156
160struct FileEntry {
161 int path_index; // Index into shared path registry
163
165
166 FileEntry(int pathIdx, const char* fileName) : path_index(pathIdx) {
167 name.set(fileName);
168 }
169};
170
175 public:
176 virtual void addName(const char* nameWithPath) = 0;
177};
178
184class NamePrinter : public Print {
185 public:
186 NamePrinter(PathNamesRegistry& dataSource, const char* prefix = nullptr)
187 : dataSource(dataSource), prefix(prefix) {}
188 void setPrefix(const char* prefix) { this->prefix = prefix; }
189 size_t write(uint8_t ch) override {
190 if (ch == '\n' || ch == '\r') {
191 // End of line - process the accumulated line
192 if (line_buffer.length() > 0) {
193 line_buffer.trim();
194 if (prefix != nullptr) {
195 // Prepend prefix if set
196 Str name{prefix};
197 name.add("/");
198 name.add(line_buffer.c_str());
199 LOGD("adding '%s'", name.c_str());
200 dataSource.addName(name.c_str());
201 } else {
202 // Add line as is
203 LOGD("adding '%s'", line_buffer.c_str());
204 dataSource.addName(line_buffer.c_str());
205 }
206 line_buffer.clear(false);
207 }
208 return 1;
209 } else {
210 // Accumulate characters
211 line_buffer.add((char)ch);
212 return 1;
213 }
214 }
215
216 size_t write(const uint8_t* buffer, size_t size) override {
217 for (size_t i = 0; i < size; i++) {
218 write(buffer[i]);
219 }
220 return size;
221 }
222
224 void flush() override {
225 if (line_buffer.length() > 0) {
226 dataSource.addName(line_buffer.c_str());
227 line_buffer.clear();
228 }
229 }
230
231 private:
232 PathNamesRegistry& dataSource;
233 Str line_buffer{200}; // Buffer to accumulate characters for each line
234 const char* prefix = nullptr;
235};
236
255template <typename FileType>
257 public:
258 typedef FileType* (*FileToStreamCallback)(const char* path,
260
261 AudioSourceVector() = default;
262
266
268 bool begin() override {
269 TRACED();
270 current_index = 0;
271 current_stream = nullptr;
272 return true;
273 }
274
276 virtual FileType* nextStream(int offset) override {
277 TRACED();
278 if (files.empty()) return nullptr;
279
280 current_index += offset;
281 // Wrap around if out of bounds
282 if (current_index < 0) {
283 current_index = files.size() - 1;
284 } else if (current_index >= (int)files.size()) {
285 current_index = 0;
286 }
287
289 }
290
292 virtual FileType* selectStream(int index) override {
293 TRACED();
294 if (files.empty() || index < 0 || index >= (int)files.size()) {
295 LOGE("Invalid index: %d (size: %d)", index, files.size());
296 return nullptr;
297 }
298
301 LOGI("selectStream: %d -> %s", index, fullPath.c_str());
302
305 return current_stream;
306 }
307
308 LOGE("No file to stream callback set!");
309 return nullptr;
310 }
311
313 virtual FileType* selectStream(const char* path) override {
314 TRACED();
315 if (path == nullptr) return nullptr;
316
317 int idx = indexOf(path);
318 if (idx >= 0) {
319 return selectStream(idx);
320 }
321
322 LOGE("File not found: %s", path);
323 return nullptr;
324 }
325
327 virtual int index() override { return current_index; }
328
330 int indexOf(const char* path) {
331 if (path == nullptr) return -1;
332
333 // Find the file by path
334 for (int i = 0; i < (int)files.size(); i++) {
336 if (fullPath.equals(path)) {
337 return i;
338 }
339 }
340 return -1;
341 }
342
344 void addName(const char* nameWithPath) override {
345 TRACED();
346 if (nameWithPath == nullptr) return;
347 LOGI("addName: '%s'", nameWithPath);
348
349 // Split path and name
351 int lastSlashPos = nameWithPathStr.lastIndexOf("/");
352 int len = nameWithPathStr.length();
353
354 Str pathStr;
355 Str nameStr;
356 if (lastSlashPos < 0) {
357 // No path, just name
358 pathStr.set("");
360 } else {
361 // Split into path and name
363 nameStr.substring(nameWithPath, lastSlashPos + 1, len);
364 }
365
366 // Find or add path to registry
367 int pathIndex = findOrAddPath(pathStr.c_str());
368
369 // Create file entry with path index
370 FileEntry entry{pathIndex, nameStr.c_str()};
371 files.push_back(entry);
372
373 }
374
376 bool deleteName(const char* nameWithPath) {
377 TRACED();
378 if (nameWithPath == nullptr) return false;
379
380 int idx = indexOf(nameWithPath);
381 if (idx >= 0) {
382 LOGI("deleteName: '%s' at index %d", nameWithPath, idx);
383 return deleteIndex(idx);
384 }
385
386 LOGW("deleteName: File not found: '%s'", nameWithPath);
387 return false;
388 }
389
391 bool deleteIndex(size_t idx) {
392 TRACED();
393 if (idx >= files.size()) {
394 LOGW("deleteIndex: Invalid index: %d (size: %d)", (int)idx, files.size());
395 return false;
396 }
397
398 LOGI("deleteIndex: Removing file at index %d", (int)idx);
399 files.erase(files.begin() + idx);
400
401 // Adjust current_index if necessary
402 if (current_index >= (int)idx) {
404 if (current_index < 0 && !files.empty()) {
405 current_index = 0;
406 }
407 }
408
409 return true;
410 }
411
413 template <typename T, size_t N>
414 void addNames(T (&nameArray)[N]) {
415 for (size_t i = 0; i < N; i++) {
416 addName(nameArray[i]);
417 }
418 }
419
421 void clear() {
422 files.clear();
423 path_registry.clear();
424 current_index = 0;
425 current_stream = nullptr;
426 }
427
429 int size() { return files.size(); }
430
432 bool isEmpty() { return files.empty(); }
433
438
441 if (current_stream) {
442 return *current_stream;
443 }
444 static FileType empty;
445 return empty;
446 }
447
449 virtual const char* toStr() override {
450 if (current_index >= 0 && current_index < (int)files.size()) {
452 return current_path.c_str();
453 }
454 return nullptr;
455 }
456
458 const char* name(int index) { return getFullPath(index).c_str(); }
459
460 protected:
461 Vector<FileEntry> files; // List of all files
462 Vector<Str> path_registry; // Shared registry of unique paths
466 Str current_path; // Cache for toStr() method
467
469 int findOrAddPath(const char* path) {
470 if (path == nullptr) path = "";
471
472 // Search for existing path
473 for (int i = 0; i < (int)path_registry.size(); i++) {
474 if (strcmp(path_registry[i].c_str(), path) == 0) {
475 return i; // Found existing path
476 }
477 }
478
479 // Path not found, add new one
480 Str newPath;
481 newPath.set(path);
482 path_registry.push_back(newPath);
483 return path_registry.size() - 1;
484 }
485
487 FileEntry& getFileEntry(int index) const { return files[index]; }
488
491 if (index < 0 || index >= (int)files.size()) {
492 return Str();
493 }
494
495 FileEntry& entry = getFileEntry(index);
496
497 // Get path
498 Str result;
499 if (entry.path_index >= 0 && entry.path_index < (int)path_registry.size()) {
500 result = path_registry[entry.path_index].c_str();
501 }
502 // delimite with /
503 if (!result.endsWith("/") && !entry.name.startsWith("/")) {
504 result.add("/");
505 }
506 // add name
507 result.add(entry.name.c_str());
508
509 return result;
510 }
511
513 const char* getPath(int pathIndex) {
514 if (pathIndex >= 0 && pathIndex < (int)path_registry.size()) {
515 return path_registry[pathIndex].c_str();
516 }
517 return "";
518 }
519};
520
538template <typename FileType>
540 public:
541 typedef FileType* (*FileToStreamCallback)(const char* path, FileType& file);
542
543 AudioSourceArray() = default;
544
546 template <size_t N>
549
551 AudioSourceArray(const char* const* nameArray, size_t size,
552 FileToStreamCallback callback)
555 nameToStreamCallback(callback) {}
556
558 virtual bool begin() override {
559 TRACED();
560 current_index = 0;
561 current_stream = nullptr;
562 return true;
563 }
564
566 virtual FileType* nextStream(int offset) override {
567 TRACED();
568 if (array_size == 0) return nullptr;
569
570 current_index += offset;
571 // Wrap around if out of bounds
572 if (current_index < 0) {
574 } else if (current_index >= (int)array_size) {
575 current_index = 0;
576 }
577
579 }
580
582 virtual FileType* selectStream(int index) override {
583 TRACED();
584 if (array_size == 0 || index < 0 || index >= (int)array_size) {
585 LOGE("Invalid index: %d (size: %d)", index, array_size);
586 return nullptr;
587 }
588
590 const char* filePath = file_array[index];
591 LOGI("selectStream: %d -> %s", index, filePath);
592
595 return current_stream;
596 }
597
598 LOGE("No file to stream callback set or invalid file path!");
599 return nullptr;
600 }
601
603 virtual FileType* selectStream(const char* path) override {
604 TRACED();
605 if (path == nullptr) return nullptr;
606
607 int idx = indexOf(path);
608 if (idx >= 0) {
609 return selectStream(idx);
610 }
611
612 LOGE("File not found: %s", path);
613 return nullptr;
614 }
615
617 virtual int index() override { return current_index; }
618
620 int indexOf(const char* path) {
621 if (path == nullptr) return -1;
622
623 // Find the file by path
624 for (int i = 0; i < (int)array_size; i++) {
625 const char* filePath = file_array[i];
626 if (filePath && StrView(path).equals(filePath)) {
627 return i;
628 }
629 }
630 return -1;
631 }
632
634 template <size_t N>
635 void setArray(const char* (&nameArray)[N]) {
637 array_size = N;
638 current_index = 0;
639 }
640
642 void setArray(const char* const* nameArray, size_t size) {
645 current_index = 0;
646 }
647
649 int size() const { return array_size; }
650
652 bool isEmpty() const { return array_size == 0; }
653
658
660 if (current_stream) {
661 return *current_stream;
662 }
663 static FileType empty;
664 return empty;
665 }
666
668 const char* getFilePath(int index) const {
669 if (index >= 0 && index < (int)array_size && file_array) {
670 return file_array[index];
671 }
672 return nullptr;
673 }
674
676 virtual const char* toStr() override {
677 if (current_index >= 0 && current_index < (int)array_size && file_array) {
679 }
680 return nullptr;
681 }
682
684 const char* name(int index) { return getFilePath(index); }
685
686 protected:
687 const char* const* file_array = nullptr; // Pointer to array of const char*
688 size_t array_size = 0;
692};
693
694} // namespace audio_tools
#define LOGW(...)
Definition AudioLoggerIDF.h:29
#define TRACED()
Definition AudioLoggerIDF.h:31
#define LOGI(...)
Definition AudioLoggerIDF.h:28
#define LOGD(...)
Definition AudioLoggerIDF.h:27
#define LOGE(...)
Definition AudioLoggerIDF.h:30
Definition Arduino.h:56
Definition Arduino.h:136
Audio Data Source managing a static array of file names (const char*). Designed for PROGMEM storage o...
Definition AudioSource.h:539
virtual FileType * selectStream(int index) override
Returns audio stream at the indicated index.
Definition AudioSource.h:582
void setArray(const char *const *nameArray, size_t size)
Set the array with pointer and size.
Definition AudioSource.h:642
void setArray(const char *(&nameArray)[N])
Set the array of file names.
Definition AudioSource.h:635
virtual const char * toStr() override
provides the actual stream (e.g. file) name or url
Definition AudioSource.h:676
void setNameToStreamCallback(FileToStreamCallback callback)
Set the callback for converting file path to stream.
Definition AudioSource.h:655
virtual bool begin() override
Reset actual stream and move to root.
Definition AudioSource.h:558
const char * getFilePath(int index) const
Get file path at index.
Definition AudioSource.h:668
const char *const * file_array
Definition AudioSource.h:687
FileType & getCurrentFile()
Definition AudioSource.h:659
const char * name(int index)
provides the name at the given index
Definition AudioSource.h:684
virtual FileType * nextStream(int offset) override
Returns next audio stream.
Definition AudioSource.h:566
AudioSourceArray(const char *(&nameArray)[N], FileToStreamCallback callback)
Constructor with array and callback.
Definition AudioSource.h:547
int current_index
Definition AudioSource.h:689
virtual FileType * selectStream(const char *path) override
Returns audio stream by path.
Definition AudioSource.h:603
FileType * current_stream
Definition AudioSource.h:690
virtual int index() override
Returns the actual index of the stream.
Definition AudioSource.h:617
bool isEmpty() const
Check if empty.
Definition AudioSource.h:652
AudioSourceArray(const char *const *nameArray, size_t size, FileToStreamCallback callback)
Constructor with array pointer, size and callback.
Definition AudioSource.h:551
FileToStreamCallback nameToStreamCallback
Definition AudioSource.h:691
size_t array_size
Definition AudioSource.h:688
FileType *(* FileToStreamCallback)(const char *path, FileType &file)
Definition AudioSource.h:541
int indexOf(const char *path)
Find index of file by path.
Definition AudioSource.h:620
int size() const
Get the number of files.
Definition AudioSource.h:649
Callback Audio Data Source which is used by the Audio Players.
Definition AudioSource.h:86
void setCallbackOnStart(void(*callback)())
Definition AudioSource.h:132
Stream *(* nextStreamCallback)(int offset)
Definition AudioSource.h:152
const char * path
Definition AudioSource.h:154
virtual Stream * selectStream(int index) override
Returns selected audio stream.
Definition AudioSource.h:112
virtual bool begin() override
Reset actual stream and move to root.
Definition AudioSource.h:98
void(* onStartCallback)()
Definition AudioSource.h:150
AudioSourceCallback(Stream *(*nextStreamCallback)(int offset), void(*onStartCallback)()=nullptr)
Definition AudioSource.h:90
void setCallbackSelectStream(Stream *(*callback)(int idx))
Definition AudioSource.h:138
virtual Stream * nextStream(int offset) override
Definition AudioSource.h:106
AudioSourceCallback()
Definition AudioSource.h:88
void setCallbackNextStream(Stream *(*callback)(int offset))
Definition AudioSource.h:134
virtual void setAutoNext(bool a)
Definition AudioSource.h:144
Stream *(* indexStreamCallback)(int index)
Definition AudioSource.h:153
virtual const char * getPath()
Returns the requested path: relevant when provided idx in callback is -1.
Definition AudioSource.h:147
virtual bool isAutoNext() override
Returns default setting go to the next.
Definition AudioSource.h:142
virtual Stream * selectStream(const char *path) override
Returns audio stream by path.
Definition AudioSource.h:127
bool auto_next
Definition AudioSource.h:151
Abstract Audio Data Source for the AudioPlayer which is used by the Audio Players.
Definition AudioSource.h:17
virtual int index()
Returns the actual index of the stream.
Definition AudioSource.h:39
virtual Stream * selectStream(const char *path)=0
Returns audio stream by path: The index is not changed!
virtual void setTimeoutAutoNext(int millisec)
Definition AudioSource.h:46
virtual void setTimeout(int millisec)
Sets the timeout of Stream in milliseconds.
Definition AudioSource.h:61
virtual Stream * selectStream(int index)
Definition AudioSource.h:30
virtual void setAutoNext(bool flag)
Definition AudioSource.h:67
virtual Stream * previousStream(int offset)
Returns previous audio stream.
Definition AudioSource.h:26
virtual Stream * setIndex(int index)
same as selectStream - I just prefer this name
Definition AudioSource.h:36
virtual bool isAutoNext()
Returns default setting go to the next.
Definition AudioSource.h:64
virtual bool setMetadataCallback(void(*fn)(MetaDataType info, const char *str, int len), ID3TypeSelection sel=SELECT_ICY)
Definition AudioSource.h:54
virtual Stream * nextStream(int offset)=0
Returns next audio stream.
virtual const char * toStr()
provides the actual stream (e.g. file) name or url
Definition AudioSource.h:73
virtual int timeoutAutoNext()
Provides the timeout which is triggering to move to the next stream.
Definition AudioSource.h:51
int timeout_auto_next_value
Definition AudioSource.h:76
bool is_auto_next
Definition AudioSource.h:77
Stream * operator[](int idx)
access with array syntax
Definition AudioSource.h:70
virtual bool begin()=0
Reset actual stream and move to root.
Flexible Audio Data Source using a Vector of (file) names with minimal RAM usage. Files are stored wi...
Definition AudioSource.h:256
virtual FileType * selectStream(int index) override
Returns audio stream at the indicated index.
Definition AudioSource.h:292
virtual const char * toStr() override
provides the actual stream (e.g. file) name or url
Definition AudioSource.h:449
void setNameToStreamCallback(FileToStreamCallback callback)
Set the callback for converting file path to stream.
Definition AudioSource.h:435
AudioSourceVector(FileToStreamCallback callback)
Constructor with callback for file to stream conversion.
Definition AudioSource.h:264
Vector< FileEntry > files
Definition AudioSource.h:461
Str current_path
Definition AudioSource.h:466
Str getFullPath(int index)
Get full path of file at index.
Definition AudioSource.h:490
Vector< Str > path_registry
Definition AudioSource.h:462
FileType & getCurrentFile()
Get the current file reference for use in callback.
Definition AudioSource.h:440
const char * name(int index)
provides the name at the given index
Definition AudioSource.h:458
virtual FileType * nextStream(int offset) override
Returns next audio stream.
Definition AudioSource.h:276
bool deleteName(const char *nameWithPath)
Remove a file by full path.
Definition AudioSource.h:376
int current_index
Definition AudioSource.h:463
int findOrAddPath(const char *path)
Find existing path in registry or add new one, returns index.
Definition AudioSource.h:469
virtual FileType * selectStream(const char *path) override
Returns audio stream by path.
Definition AudioSource.h:313
FileType * current_stream
Definition AudioSource.h:464
void addNames(T(&nameArray)[N])
Add multiple files at once.
Definition AudioSource.h:414
virtual int index() override
Returns the actual index of the stream.
Definition AudioSource.h:327
void clear()
Clear all files and path registry.
Definition AudioSource.h:421
bool begin() override
Reset actual stream and move to root.
Definition AudioSource.h:268
FileEntry & getFileEntry(int index) const
Get file entry at index.
Definition AudioSource.h:487
const char * getPath(int pathIndex)
Get path from registry at index.
Definition AudioSource.h:513
void addName(const char *nameWithPath) override
Add a file with full path (path and name will be separated automatically)
Definition AudioSource.h:344
FileToStreamCallback nameToStreamCallback
Definition AudioSource.h:465
bool deleteIndex(size_t idx)
Remove a file by index.
Definition AudioSource.h:391
int indexOf(const char *path)
Find index of file by path.
Definition AudioSource.h:330
FileType *(* FileToStreamCallback)(const char *path, FileType &oldFile)
Definition AudioSource.h:258
bool isEmpty()
Check if empty.
Definition AudioSource.h:432
int size()
Get the number of files.
Definition AudioSource.h:429
Print class that calls addName for each printed line. Useful for collecting file names from text outp...
Definition AudioSource.h:184
void flush() override
Flush any remaining content in the line buffer.
Definition AudioSource.h:224
size_t write(const uint8_t *buffer, size_t size) override
Definition AudioSource.h:216
NamePrinter(PathNamesRegistry &dataSource, const char *prefix=nullptr)
Definition AudioSource.h:186
size_t write(uint8_t ch) override
Definition AudioSource.h:189
void setPrefix(const char *prefix)
Definition AudioSource.h:188
Interface for classes that can collect file names.
Definition AudioSource.h:174
virtual void addName(const char *nameWithPath)=0
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
void clear() override
clears and resizes to 0
Definition Str.h:167
A simple wrapper to provide string functions on existing allocated char*. If the underlying char* is ...
Definition StrView.h:28
virtual bool equals(const char *str)
checks if the string equals indicated parameter string
Definition StrView.h:165
virtual bool endsWith(const char *str)
checks if the string ends with the indicated substring
Definition StrView.h:178
virtual int length()
Definition StrView.h:384
virtual bool startsWith(const char *str)
checks if the string starts with the indicated substring
Definition StrView.h:171
virtual void trim()
remove leading and traling spaces
Definition StrView.h:505
virtual void set(const char *alt)
assigs a value
Definition StrView.h:47
virtual void substring(StrView &from, int start, int end)
copies a substring into the current string
Definition StrView.h:478
virtual const char * c_str()
provides the string value as const char*
Definition StrView.h:380
virtual void add(int value)
adds a int value
Definition StrView.h:126
Vector implementation which provides the most important methods as defined by std::vector....
Definition Vector.h:21
ID3TypeSelection
Enum to filter by type of metadata.
Definition AbstractMetaData.h:8
MetaDataType
Type of meta info.
Definition AbstractMetaData.h:11
@ SELECT_ICY
Definition AbstractMetaData.h:8
Generic Implementation of sound input and output for desktop environments using portaudio.
Definition AudioCodecsBase.h:10
size_t writeData(Print *p_out, T *data, int samples, int maxSamples=512)
Definition AudioTypes.h:508
File entry to minimize RAM usage by using path index and name.
Definition AudioSource.h:160
int path_index
Definition AudioSource.h:161
Str name
Definition AudioSource.h:162
FileEntry()
Definition AudioSource.h:164
FileEntry(int pathIdx, const char *fileName)
Definition AudioSource.h:166