RSeries astromech firmware
Warbler.h
Go to the documentation of this file.
1 #ifndef Warbler_h
2 
3 #if !defined(ESP32)
4 #error Only supports ESP32
5 #endif
6 
7 #include "ReelTwo.h"
8 #include "core/SetupEvent.h"
9 #include "core/AnimatedEvent.h"
11 #include "audio/AudioPlayer.h"
12 
13 //#define MIX_AUDIO_FLOAT
14 
15 #ifdef USE_WARBLER_DEBUG
16 #define WARBLER_DEBUG_PRINT(s) DEBUG_PRINT(s)
17 #define WARBLER_DEBUG_PRINTLN(s) DEBUG_PRINTLN(s)
18 #define WARBLER_DEBUG_PRINT_HEX(s) DEBUG_PRINT_HEX(s)
19 #define WARBLER_DEBUG_PRINTLN_HEX(s) DEBUG_PRINTLN_HEX(s)
20 #else
21 #define WARBLER_DEBUG_PRINT(s)
22 #define WARBLER_DEBUG_PRINTLN(s)
23 #define WARBLER_DEBUG_PRINT_HEX(s)
24 #define WARBLER_DEBUG_PRINTLN_HEX(s)
25 #endif
26 
27 #ifndef WARBLER_NUM_TRACKS
28 #define WARBLER_NUM_TRACKS 10
29 #endif
30 
31 #ifndef WARBLER_QUEUE_DEPTH
32 #define WARBLER_QUEUE_DEPTH 10
33 #endif
34 
35 #ifndef WARBLER_DECODE_BUFFER_SIZE
36 #define WARBLER_DECODE_BUFFER_SIZE 2048
37 #endif
38 
39 #ifndef I2S_DOUT_PIN
40 #define I2S_DOUT_PIN 25 // I2S audio output
41 #endif
42 
43 #ifndef I2S_LRC_PIN
44 #define I2S_LRC_PIN 26 // I2S audio output
45 #endif
46 
47 #ifndef I2S_BCLK_PIN
48 #define I2S_BCLK_PIN 27 // I2S audio output
49 #endif
50 
51 class WarblerAudio: public AnimatedEvent, public SetupEvent, protected AudioPlayer
52 {
53 public:
54  WarblerAudio(fs::FS &fs, AudioFrequencyBitmap* audioBitmap = nullptr,
55  uint8_t bclk = I2S_BCLK_PIN, uint8_t lrc = I2S_LRC_PIN, uint8_t dout = I2S_DOUT_PIN) :
56  fAudioBitmap(audioBitmap),
57  fFS(fs)
58  {
59  *fNextSong = '\0';
60  setPinout(bclk, lrc, dout);
61  }
62 
63  void setBalance(int8_t bal = 0)
64  {
66  }
67 
68  void setVolume(uint8_t vol)
69  {
71  }
72 
73  inline bool isComplete() const
74  {
75  return fActiveRemaining == 0;
76  }
77 
78  void stop()
79  {
80  fStopStream = true;
81  }
82 
83  virtual void setup() override
84  {
85  xTaskCreatePinnedToCore(
86  audioLoopTask,
87  "WarblerAudio",
88  10000,
89  nullptr,
90  1,
91  &fAudioTask,
92  0);
93  fPOD = esp_partition_find_first((esp_partition_type_t)0xBA, (esp_partition_subtype_t)0xBE, NULL);
94  if (initTracks())
95  setSampleFilter(audioFilter);
96  }
97 
98  virtual void animate() override
99  {
100  if (fActiveRemaining != 0)
101  return;
102  if (fNextTrack == -1 && fNextWarble == -1 && fNumQueue > 0)
103  {
104  uint32_t now = millis();
105  if (fQueue->fStartMS == 0)
106  fQueue->fStartMS = now;
107  if (fQueue->fStartMS + fQueue->fDelayMS <= now)
108  {
109  fNextTrack = fQueue->fTrack;
110  fNextWarble = fQueue->fWarble;
111  // printf("Play %d:%d\n", fNextTrack, fNextWarble);
112  if (--fNumQueue > 0)
113  {
114  memmove(&fQueue[0], &fQueue[1], fNumQueue * sizeof(fQueue[0]));
115  // printf("Remaining: %d\n", fNumQueue);
116  }
117  }
118  }
119  if (fNextTrack != -1 && fNextWarble != -1)
120  {
121  // DEBUG_PRINT("NEXT WARBLE ["); DEBUG_PRINT(fNextTrack);
122  // DEBUG_PRINT(":"); DEBUG_PRINT(fNextWarble); DEBUG_PRINTLN("]");
123  if (fPOD != nullptr && isPlaying())
124  {
125  static uint32_t sPODOffset[110] = {
126  64000, 87040, 131328, 176640, 209152, 303104, 357888, 418560, 439296, 512512, 555776,
127  593408, 643328, 698112, 783872, 813056, 850944, 923136, 975104, 1055744, 1090304, 1150720,
128  1304064, 1555968, 1709568, 1837568, 1912064, 2061056, 2269184, 2422016, 2546688, 2652160, 2775808,
129  2843392, 2921216, 3008768, 3069952, 3136000, 3173120, 3241728, 3321856, 3341312, 3398656, 3410944,
130  3565568, 3630848, 3755264, 3881728, 4005376, 4120320, 4211968, 4301568, 4420608, 4509440, 4586496,
131  4640000, 4764672, 4835072, 4884480, 4943616, 5020928, 5113600, 5208064, 5277184, 5344000, 5417984,
132  5560320, 5673216, 5822464, 5968384, 6058496, 6175744, 6312704, 6471936, 6581248, 6676992, 6781184,
133  6813440, 6871808, 6924544, 6967040, 7025408, 7095808, 7159040, 7203328, 7293440, 7323392, 7346176,
134  7423744, 7536640, 7610880, 7708160, 7787776, 7863040, 8000256, 8076800, 8157952, 8200448, 8332288,
135  8492800, 8616704, 8713728, 8941568, 9273600, 9448704, 9582592, 9729536, 9876224, 10041344, 10285056
136  };
137  uint32_t warbleOffset = 0;
138  uint32_t warbleLength = 0;
139  uint32_t activeRemaining = 0;
140  const int numWarbles = SizeOfArray(sPODOffset) / SizeOfArray(fTrackCount);
141  if (fNextWarble > numWarbles)
142  fNextWarble = int(float(fNextWarble) / fTrackCount[fNextTrack] * numWarbles);
143  uint32_t warbleTrack = fNextWarble + fNextTrack * numWarbles;
144  warbleOffset = (warbleTrack > 0) ? sPODOffset[warbleTrack-1] : 0;
145  warbleLength = sPODOffset[warbleTrack];
146  activeRemaining = warbleLength - warbleOffset;
147  fPODActive = true;
148  fPODOffset = warbleOffset;
149  if (activeRemaining > 0)
150  clearDecodeBuffer();
151  fActiveRemaining = activeRemaining;
152  if (activeRemaining > 0 && !isPlaying())
153  connecttonull();
154  }
155  else
156  {
157  fPODActive = false;
158  if (fNextTrack != fActiveTrack)
159  {
160  if (fActiveTrack != -1)
161  closeTrack();
162  openTrack(fNextTrack);
163  }
164  // DEBUG_PRINTLN(fActiveTrack);
165  if (fActiveTrack != -1)
166  {
167  uint32_t offsetTable;
168  uint32_t trackCount = 0;
169  uint32_t warbleOffset = 0;
170  uint32_t warbleLength = 0;
171  uint32_t activeRemaining = 0;
172  // DEBUG_PRINT("TABLE: "); DEBUG_PRINTLN((uint32_t)fTrackOffset[fActiveTrack]);
173  if (fTrackOffset[fActiveTrack] != nullptr)
174  {
175  warbleOffset = (fNextWarble > 0) ? fTrackOffset[fActiveTrack][fNextWarble-1] : 0;
176  warbleLength = fTrackOffset[fActiveTrack][fNextWarble];
177  activeRemaining = warbleLength - warbleOffset;
178  // DEBUG_PRINTLN(warbleOffset);
179  if (!fFile.seek(warbleOffset + sizeof(offsetTable), SeekSet))
180  {
181  DEBUG_PRINTLN("Failed to seek");
182  activeRemaining = 0;
183  }
184  // DEBUG_PRINTLN(activeRemaining);
185  }
186  else if (fFile.seek(0, SeekSet) &&
187  fFile.read((uint8_t*)&offsetTable, sizeof(offsetTable)) == sizeof(offsetTable) &&
188  fFile.seek(offsetTable, SeekSet) &&
189  fFile.read((uint8_t*)&trackCount, sizeof(trackCount)) == sizeof(trackCount))
190  {
191  if (fNextWarble > 0)
192  {
193  if (fFile.seek((fNextWarble-1)*sizeof(warbleLength), SeekCur) &&
194  fFile.read((uint8_t*)&warbleOffset, sizeof(warbleOffset)) == sizeof(warbleOffset) &&
195  fFile.read((uint8_t*)&warbleLength, sizeof(warbleLength)) == sizeof(warbleLength))
196  {
197  activeRemaining = warbleLength - warbleOffset;
198  }
199  }
200  else if (fFile.read((uint8_t*)&warbleLength, sizeof(warbleLength)) == sizeof(warbleLength))
201  {
202  activeRemaining = warbleLength;
203  }
204  if (!fFile.seek(warbleOffset + sizeof(offsetTable), SeekSet))
205  {
206  activeRemaining = 0;
207  }
208  }
209  else
210  {
211  DEBUG_PRINTLN("Failed to locate");
212  }
213  if (activeRemaining > 0)
214  clearDecodeBuffer();
215  fActiveRemaining = activeRemaining;
216  if (activeRemaining > 0 && !isPlaying())
217  connecttonull();
218  }
219  }
220  fNextTrack = fNextWarble = -1;
221  }
222  }
223 
224  bool isPlaying()
225  {
226  return isRunning() && (isLocalFile() || isWebStream());
227  }
228 
229  void play(const char* file)
230  {
231  strncpy(fNextSong, file, sizeof(fNextSong)-1);
232  }
233 
234  void playNext(int track = -1, int32_t warble = -1)
235  {
236  if (track == -1)
237  track = random(SizeOfArray(fTrackCount));
238  track = max(min(track, int(SizeOfArray(fTrackCount))), 0);
239  if (warble == -1)
240  warble = random(fTrackCount[track]);
241  warble = max(min(warble, fTrackCount[track]), 0);
242  fNextTrack = track;
243  fNextWarble = warble;
244  }
245 
246  void queue(uint32_t delayMS = 0, int track = -1, int32_t warble = -1)
247  {
248  if (track == -1)
249  track = random(SizeOfArray(fTrackCount));
250  track = max(min(track, int(SizeOfArray(fTrackCount))), 0);
251  if (warble == -1)
252  warble = random(fTrackCount[track]);
253  warble = max(min(warble, fTrackCount[track]), 0);
254  if (fNumQueue < SizeOfArray(fQueue))
255  {
256  fQueue[fNumQueue].fTrack = track;
257  fQueue[fNumQueue].fWarble = warble;
258  fQueue[fNumQueue].fStartMS = 0;
259  fQueue[fNumQueue].fDelayMS = delayMS;
260  fNumQueue++;
261  }
262  }
263 
264 #ifdef MIX_AUDIO_FLOAT
265  float read()
266 #else
267  int16_t read()
268 #endif
269  {
270  static short sDecode[256] =
271  {
272  -32124, -31100, -30076, -29052, -28028, -27004, -25980, -24956,
273  -23932, -22908, -21884, -20860, -19836, -18812, -17788, -16764,
274  -15996, -15484, -14972, -14460, -13948, -13436, -12924, -12412,
275  -11900, -11388, -10876, -10364, -9852, -9340, -8828, -8316,
276  -7932, -7676, -7420, -7164, -6908, -6652, -6396, -6140,
277  -5884, -5628, -5372, -5116, -4860, -4604, -4348, -4092,
278  -3900, -3772, -3644, -3516, -3388, -3260, -3132, -3004,
279  -2876, -2748, -2620, -2492, -2364, -2236, -2108, -1980,
280  -1884, -1820, -1756, -1692, -1628, -1564, -1500, -1436,
281  -1372, -1308, -1244, -1180, -1116, -1052, -988, -924,
282  -876, -844, -812, -780, -748, -716, -684, -652,
283  -620, -588, -556, -524, -492, -460, -428, -396,
284  -372, -356, -340, -324, -308, -292, -276, -260,
285  -244, -228, -212, -196, -180, -164, -148, -132,
286  -120, -112, -104, -96, -88, -80, -72, -64,
287  -56, -48, -40, -32, -24, -16, -8, 0,
288 
289  32124, 31100, 30076, 29052, 28028, 27004, 25980, 24956,
290  23932, 22908, 21884, 20860, 19836, 18812, 17788, 16764,
291  15996, 15484, 14972, 14460, 13948, 13436, 12924, 12412,
292  11900, 11388, 10876, 10364, 9852, 9340, 8828, 8316,
293  7932, 7676, 7420, 7164, 6908, 6652, 6396, 6140,
294  5884, 5628, 5372, 5116, 4860, 4604, 4348, 4092,
295  3900, 3772, 3644, 3516, 3388, 3260, 3132, 3004,
296  2876, 2748, 2620, 2492, 2364, 2236, 2108, 1980,
297  1884, 1820, 1756, 1692, 1628, 1564, 1500, 1436,
298  1372, 1308, 1244, 1180, 1116, 1052, 988, 924,
299  876, 844, 812, 780, 748, 716, 684, 652,
300  620, 588, 556, 524, 492, 460, 428, 396,
301  372, 356, 340, 324, 308, 292, 276, 260,
302  244, 228, 212, 196, 180, 164, 148, 132,
303  120, 112, 104, 96, 88, 80, 72, 64,
304  56, 48, 40, 32, 24, 16, 8, 0
305  };
306  #ifdef MIX_AUDIO_FLOAT
307  float sample = 0;
308  #else
309  int16_t sample = 0;
310  #endif
311  if (fActiveRemaining > 0)
312  {
313  if (fDecodePtr == &fDecodeBuffer[sizeof(fDecodeBuffer)])
314  fillDecodeBuffer();
315  #ifdef MIX_AUDIO_FLOAT
316  sample = float(sDecode[*fDecodePtr++]) / SHRT_MAX;
317  #else
318  sample = sDecode[*fDecodePtr++];
319  #endif
320  fActiveRemaining--;
321  }
322  return sample;
323  }
324 
325  virtual void audio_eof_mp3(const char *info) override
326  {
327  // connecttonull();
328  }
329 
330 private:
331  File fFile;
332  TaskHandle_t fAudioTask = nullptr;
333  int fNextTrack = -1;
334  int fNextWarble = -1;
335  unsigned fNumQueue = 0;
336  bool fOTAInProgress = false;
337  struct {
338  int fTrack;
339  int fWarble;
340  uint32_t fStartMS;
341  uint32_t fDelayMS;
342  } fQueue[WARBLER_QUEUE_DEPTH];
343  int8_t fActiveTrack = -1;
344  uint32_t fActiveRemaining = 0;
345  uint8_t fDecodeBuffer[WARBLER_DECODE_BUFFER_SIZE];
346  uint8_t* fDecodePtr = &fDecodeBuffer[sizeof(fDecodeBuffer)];
347  int32_t fTrackCount[WARBLER_NUM_TRACKS] = {};
348  uint32_t* fTrackOffset[WARBLER_NUM_TRACKS] = {};
349  AudioFrequencyBitmap* fAudioBitmap = nullptr;
350  const esp_partition_t* fPOD = nullptr;
351  bool fPODActive = false;
352  uint32_t fPODOffset = 0;
353  fs::FS &fFS;
354  bool fStopStream = false;
355  char fNextSong[128];
356 
357  void clearDecodeBuffer()
358  {
359  fDecodePtr = &fDecodeBuffer[sizeof(fDecodeBuffer)];
360  }
361 
362  void fillDecodeBuffer()
363  {
364  ssize_t bytesRead;
365  fDecodePtr = fDecodeBuffer;
366  if (fPODActive)
367  {
368  bytesRead = min(fActiveRemaining, sizeof(fDecodeBuffer));
369  if (esp_partition_read(fPOD, fPODOffset, fDecodeBuffer, bytesRead) != ESP_OK)
370  {
371  bytesRead = 0;
372  }
373  fPODOffset += bytesRead;
374  }
375  else
376  {
377  // dont care about errors output will be silent
378  bytesRead = fFile.readBytes((char*)fDecodeBuffer, sizeof(fDecodeBuffer));
379  }
380  // should never but if we have a read failure or underrun clear to zero
381  if (bytesRead < 0)
382  bytesRead = 0;
383  if (bytesRead != sizeof(fDecodeBuffer))
384  {
385  memset(&fDecodeBuffer[bytesRead], '\0', sizeof(fDecodeBuffer) - bytesRead);
386  }
387  }
388 
389  static WarblerAudio*& activeWarbler()
390  {
391  static WarblerAudio* sWarbler;
392  return sWarbler;
393  }
394 
395  bool openTrack(unsigned i)
396  {
397  char buf[16];
398  snprintf(buf, sizeof(buf), "/sys%d.dat", i);
399  fFile = fFS.open(buf);
400  fActiveTrack = i;
401  return (fFile == true);
402  }
403 
404  void closeTrack()
405  {
406  fFile.close();
407  fActiveTrack = -1;
408  }
409 
410  bool initTracks()
411  {
412  if (!psramInit())
413  return false;
414  bool success = (activeWarbler() == nullptr);
415  for (unsigned i = 0; i < SizeOfArray(fTrackCount); i++)
416  {
417  if (openTrack(i))
418  {
419  uint32_t offsetTable;
420  int32_t trackCount;
421  if (fFile.seek(0, SeekSet) &&
422  fFile.read((uint8_t*)&offsetTable, sizeof(offsetTable)) == sizeof(offsetTable) &&
423  fFile.seek(offsetTable, SeekSet) &&
424  fFile.read((uint8_t*)&trackCount, sizeof(trackCount)) == sizeof(trackCount))
425  {
426  fTrackCount[i] = trackCount;
427  fTrackOffset[i] = nullptr;
428  // fTrackOffset[i] = (uint32_t*)ps_calloc(trackCount, sizeof(uint32_t));
430  WARBLER_DEBUG_PRINT(": "); WARBLER_DEBUG_PRINT(trackCount);
431  WARBLER_DEBUG_PRINT(" tableSize: "); WARBLER_DEBUG_PRINTLN(trackCount * sizeof(uint32_t));
432  // if (fTrackOffset[i] != nullptr)
433  // {
434  // size_t trackOffsetSize = trackCount*sizeof(uint32_t);
435  // if (fFile.read((uint8_t*)fTrackOffset[i], trackOffsetSize) != trackOffsetSize)
436  // {
437  // // Failed to read track offsets disable track
438  // WARBLER_DEBUG_PRINTLN("Failed to read offset table");
439  // free(fTrackOffset[i]);
440  // fTrackOffset[i] = nullptr;
441  // fTrackCount[i] = 0;
442  // }
443  // else
444  // {
445  // DEBUG_PRINTLN_HEX((uint32_t)fTrackOffset[i]);
446  // }
447  // }
448  // else
449  // {
450  // WARBLER_DEBUG_PRINTLN("Failed to allocate offset table");
451  // }
452  }
453  closeTrack();
454  }
455  else
456  {
457  success = false;
458  }
459  }
460  if (success)
461  activeWarbler() = this;
462  return success;
463  }
464 
465  static inline float mixSamples(float s1, float s2)
466  {
467  s1 = (s1 + s2) - (s1 * s2);
468  // // clip if necessary
469  // if (s1 < -1.0f)
470  // s1 = -1.0f;
471  // if (s1 > 1.0f)
472  // s1 = 1.0f;
473  return s1;
474  }
475 
476  static void audioFilter(unsigned numBits, unsigned numChannels, const int16_t* samples, unsigned sampleCount)
477  {
478  WarblerAudio* active = activeWarbler();
479  if (active == nullptr)
480  return;
481  if (active->fActiveRemaining == 0)
482  {
483  AudioFrequencyBitmap* bitmap = active->fAudioBitmap;
484  if (!active->isNullStream() && bitmap != nullptr)
485  bitmap->processSamples(numBits, numChannels, samples, sampleCount);
486  return;
487  }
488  #ifdef MIX_AUDIO_FLOAT
489  static float sPlayVolume = 1.0f;
490  static float sTrackVolume = 1.0f;
491  if (numBits == 8)
492  {
493  uint8_t* outp = (uint8_t*)samples;
494  if (numChannels == 1)
495  {
496  for (size_t i = 0; i < sampleCount*2; i++)
497  {
498  float s2 = active->read() * sPlayVolume;
499  float s1 = (float(*outp) / UCHAR_MAX) * sTrackVolume;
500  *outp++ = uint8_t(mixSamples(s1, s2) * UCHAR_MAX);
501  }
502  }
503  else
504  {
505  for (size_t i = 0; i < sampleCount*2; i++)
506  {
507  float s2 = active->read() * sPlayVolume;
508  for (size_t ci = 0; ci < numChannels; ci++)
509  {
510  float s1 = (float(*outp) / UCHAR_MAX) * sTrackVolume;
511  *outp++ = uint8_t(mixSamples(s1, s2) * UCHAR_MAX);
512  }
513  }
514  }
515  }
516  else if (numBits == 16)
517  {
518  int16_t* outp = (int16_t*)samples;
519  if (numChannels == 1)
520  {
521  for (size_t i = 0; i < sampleCount; i++)
522  {
523  float s2 = active->read();
524  float s1 = (float(*outp) / SHRT_MAX) * sTrackVolume;
525  *outp++ = int16_t(mixSamples(s1, s2) * SHRT_MAX);
526  }
527  }
528  else
529  {
530  for (size_t i = 0; i < sampleCount; i++)
531  {
532  float s2 = active->read() * sPlayVolume;
533  for (size_t ci = 0; ci < numChannels; ci++)
534  {
535  float s1 = (float(*outp) / SHRT_MAX) * sTrackVolume;
536  *outp++ = int16_t(mixSamples(s1, s2) * SHRT_MAX);
537  }
538  }
539  }
540  }
541  #else
542  if (numBits == 8)
543  {
544  uint8_t* outp = (uint8_t*)samples;
545  if (numChannels == 1)
546  {
547  for (size_t i = 0; i < sampleCount*2; i++)
548  {
549  int32_t s2 = active->read();
550  int32_t s1 = (*outp - 0x80) << 8;
551  *outp++ = uint8_t((float((s1 + s2) - (s1 * s2)) / SHRT_MAX) * UCHAR_MAX);
552  }
553  }
554  else
555  {
556  for (size_t i = 0; i < sampleCount*2; i++)
557  {
558  int32_t s2 = active->read();
559  for (size_t ci = 0; ci < numChannels; ci++)
560  {
561  int32_t s1 = (*outp - 0x80) << 8;
562  *outp++ = uint8_t((float((s1 + s2) - (s1 * s2)) / SHRT_MAX) * UCHAR_MAX);
563  }
564  }
565  }
566  }
567  else if (numBits == 16)
568  {
569  int16_t* outp = (int16_t*)samples;
570  if (numChannels == 1)
571  {
572  for (size_t i = 0; i < sampleCount; i++)
573  {
574  int32_t s2 = active->read();
575  int32_t s1 = *outp;
576  *outp++ = (s1 + s2);
577  }
578  }
579  else
580  {
581  for (size_t i = 0; i < sampleCount; i++)
582  {
583  int32_t s2 = active->read();
584  for (size_t ci = 0; ci < numChannels; ci++)
585  {
586  int32_t s1 = *outp;
587  *outp++ = (s1 + s2);
588  }
589  }
590  }
591  }
592  #endif
593  }
594 
595  void audioLoop()
596  {
597  if (fStopStream || *fNextSong != 0)
598  {
599  fStopStream = false;
601  if (*fNextSong == '\0')
602  connecttonull();
603  }
604  if (*fNextSong)
605  {
606  if (!connecttoFS(fFS, fNextSong))
607  connecttonull();
608  *fNextSong = '\0';
609  }
610 
612  if (fOTAInProgress)
614  }
615 
616  static void audioLoopTask(void*)
617  {
618  for (;;)
619  {
620  WarblerAudio* active = activeWarbler();
621  if (active != nullptr)
622  active->audioLoop();
623  vTaskDelay(1);
624  }
625  }
626 };
627 #endif
AudioPlayer::connecttonull
bool connecttonull()
WARBLER_QUEUE_DEPTH
#define WARBLER_QUEUE_DEPTH
Definition: Warbler.h:32
WarblerAudio::audio_eof_mp3
virtual void audio_eof_mp3(const char *info) override
Definition: Warbler.h:325
WarblerAudio::setup
virtual void setup() override
Subclasses must implement this function to perform any necessary setup that cannot happen in the cons...
Definition: Warbler.h:83
AudioPlayer::isNullStream
bool isNullStream()
Definition: AudioPlayer.h:160
WARBLER_DEBUG_PRINTLN
#define WARBLER_DEBUG_PRINTLN(s)
Definition: Warbler.h:22
AudioPlayer.h
WarblerAudio::isComplete
bool isComplete() const
Definition: Warbler.h:73
WarblerAudio::fTrack
int fTrack
Definition: Warbler.h:338
AudioPlayer
Definition: AudioPlayer.h:102
WarblerAudio::animate
virtual void animate() override
Subclasses must implement this function to run through a single frame of animation/activity.
Definition: Warbler.h:98
ReelTwo.h
SetupEvent.h
WarblerAudio::read
int16_t read()
Definition: Warbler.h:267
AnimatedEvent
Base class for all animated devices. AnimatedEvent::animate() is called for each device once through ...
Definition: AnimatedEvent.h:18
WARBLER_DECODE_BUFFER_SIZE
#define WARBLER_DECODE_BUFFER_SIZE
Definition: Warbler.h:36
WarblerAudio::setBalance
void setBalance(int8_t bal=0)
Definition: Warbler.h:63
SetupEvent
Utility class to control a VMusic2 module. Provides for sound playback as well as disk access.
Definition: SetupEvent.h:15
WarblerAudio
Definition: Warbler.h:51
AudioPlayer::loop
void loop()
AnimatedEvent.h
WarblerAudio::isPlaying
bool isPlaying()
Definition: Warbler.h:224
AudioPlayer::connecttoFS
bool connecttoFS(fs::FS &fs, const char *file)
WarblerAudio::fStartMS
uint32_t fStartMS
Definition: Warbler.h:340
DEBUG_PRINTLN
#define DEBUG_PRINTLN(s)
Definition: ReelTwo.h:178
WarblerAudio::WarblerAudio
WarblerAudio(fs::FS &fs, AudioFrequencyBitmap *audioBitmap=nullptr, uint8_t bclk=I2S_BCLK_PIN, uint8_t lrc=I2S_LRC_PIN, uint8_t dout=I2S_DOUT_PIN)
Definition: Warbler.h:54
AudioPlayer::setSampleFilter
void setSampleFilter(AudioSampleFilter filter)
Definition: AudioPlayer.h:170
AnimatedEvent::process
static void process()
Calls animate() for each created AnimatedEvent subclass.
Definition: AnimatedEvent.h:38
AudioFrequencyBitmap::processSamples
void processSamples(unsigned numBits, unsigned numChannels, const int16_t *samples, int sampleCount)
Definition: AudioFrequencyBitmap.h:192
WarblerAudio::playNext
void playNext(int track=-1, int32_t warble=-1)
Definition: Warbler.h:234
WarblerAudio::setVolume
void setVolume(uint8_t vol)
Definition: Warbler.h:68
AudioPlayer::isRunning
bool isRunning()
Definition: AudioPlayer.h:159
I2S_BCLK_PIN
#define I2S_BCLK_PIN
Definition: Warbler.h:48
WarblerAudio::queue
void queue(uint32_t delayMS=0, int track=-1, int32_t warble=-1)
Definition: Warbler.h:246
WarblerAudio::stop
void stop()
Definition: Warbler.h:78
WarblerAudio::fDelayMS
uint32_t fDelayMS
Definition: Warbler.h:341
WarblerAudio::play
void play(const char *file)
Definition: Warbler.h:229
WARBLER_DEBUG_PRINT
#define WARBLER_DEBUG_PRINT(s)
Definition: Warbler.h:21
WarblerAudio::fWarble
int fWarble
Definition: Warbler.h:339
AudioPlayer::setVolume
void setVolume(uint8_t vol)
AudioPlayer::isWebStream
bool isWebStream()
Definition: AudioPlayer.h:162
AudioPlayer::setPinout
bool setPinout(uint8_t BCLK, uint8_t LRC, uint8_t DOUT, int8_t DIN=I2S_PIN_NO_CHANGE)
AudioPlayer::stopSong
void stopSong()
WARBLER_NUM_TRACKS
#define WARBLER_NUM_TRACKS
Definition: Warbler.h:28
AudioFrequencyBitmap.h
AudioPlayer::setBalance
void setBalance(int8_t bal=0)
I2S_DOUT_PIN
#define I2S_DOUT_PIN
Definition: Warbler.h:40
SizeOfArray
#define SizeOfArray(arr)
Definition: ReelTwo.h:204
I2S_LRC_PIN
#define I2S_LRC_PIN
Definition: Warbler.h:44
AudioFrequencyBitmap
Definition: AudioFrequencyBitmap.h:183
AudioPlayer::isLocalFile
bool isLocalFile()
Definition: AudioPlayer.h:161