arduino-audio-tools
Loading...
Searching...
No Matches
AudioPlayer.h
1#pragma once
2
3#include "AudioTools/AudioCodecs/AudioCodecs.h"
4#include "AudioTools/CoreAudio/AudioBasic/Debouncer.h"
5#include "AudioTools/CoreAudio/AudioHttp/AudioHttp.h"
6#include "AudioTools/CoreAudio/AudioLogger.h"
7#include "AudioTools/CoreAudio/AudioMetaData/MetaData.h"
8#include "AudioTools/CoreAudio/AudioStreams.h"
9#include "AudioTools/CoreAudio/AudioTypes.h"
10#include "AudioTools/CoreAudio/BaseConverter.h"
11#include "AudioTools/CoreAudio/Buffers.h"
12#include "AudioTools/CoreAudio/Fade.h"
13#include "AudioTools/CoreAudio/StreamCopy.h"
14#include "AudioTools/CoreAudio/VolumeStream.h"
15#include "AudioTools/Disk/AudioSource.h"
16#include "AudioToolsConfig.h"
17
24namespace audio_tools {
25
39 public:
41 AudioPlayer() { TRACED(); }
42
52 AudioPlayer(AudioSource &source, AudioOutput &output, AudioDecoder &decoder) {
53 TRACED();
54 this->p_source = &source;
55 this->p_decoder = &decoder;
56 setOutput(output);
57 // notification for audio configuration
58 decoder.addNotifyAudioChange(*this);
59 }
60
71 AudioPlayer(AudioSource &source, Print &output, AudioDecoder &decoder,
72 AudioInfoSupport *notify = nullptr) {
73 TRACED();
74 this->p_source = &source;
75 this->p_decoder = &decoder;
76 setOutput(output);
78 }
79
89 AudioPlayer(AudioSource &source, AudioStream &output, AudioDecoder &decoder) {
90 TRACED();
91 this->p_source = &source;
92 this->p_decoder = &decoder;
93 setOutput(output);
94 // notification for audio configuration
95 decoder.addNotifyAudioChange(*this);
96 }
97
98 AudioPlayer(AudioPlayer const &) = delete;
99
100 AudioPlayer &operator=(AudioPlayer const &) = delete;
101
102 void setOutput(AudioOutput &output) {
103 if (p_decoder->isResultPCM()) {
104 this->fade.setOutput(output);
105 this->volume_out.setOutput(fade);
106 out_decoding.setOutput(&volume_out);
107 out_decoding.setDecoder(p_decoder);
108 } else {
109 out_decoding.setOutput(&output);
110 out_decoding.setDecoder(p_decoder);
111 }
112 this->p_final_print = &output;
113 this->p_final_stream = nullptr;
114 }
115
116 void setOutput(Print &output) {
117 if (p_decoder->isResultPCM()) {
118 this->fade.setOutput(output);
119 this->volume_out.setOutput(fade);
120 out_decoding.setOutput(&volume_out);
121 out_decoding.setDecoder(p_decoder);
122 } else {
123 out_decoding.setOutput(&output);
124 out_decoding.setDecoder(p_decoder);
125 }
126 this->p_final_print = nullptr;
127 this->p_final_stream = nullptr;
128 }
129
130 void setOutput(AudioStream &output) {
131 if (p_decoder->isResultPCM()) {
132 this->fade.setOutput(output);
133 this->volume_out.setOutput(fade);
134 out_decoding.setOutput(&volume_out);
135 out_decoding.setDecoder(p_decoder);
136 } else {
137 out_decoding.setOutput(&output);
138 out_decoding.setDecoder(p_decoder);
139 }
140 this->p_final_print = nullptr;
141 this->p_final_stream = &output;
142 }
143
145 void setBufferSize(int size) { copier.resize(size); }
146
149 bool begin(int index = 0, bool isActive = true) {
150 TRACED();
151 bool result = false;
152 // initilaize volume
153 if (current_volume == -1.0f) {
154 setVolume(1.0f);
155 } else {
156 setVolume(current_volume);
157 }
158
159 // take definition from source
160 autonext = p_source->isAutoNext();
161
162 // initial audio info for fade from output when not defined yet
163 setupFade();
164
165 // start dependent objects
166 out_decoding.begin();
167
168 if (!p_source->begin()){
169 LOGE("Could not start audio source");
170 return false;
171 }
172 if (!meta_out.begin()){
173 LOGE("Could not start metadata output");
174 return false;
175 }
176 if (!volume_out.begin()){
177 LOGE("Could not start volume control");
178 return false;
179 }
180
181 if (index >= 0) {
182 setStream(p_source->selectStream(index));
183 if (p_input_stream != nullptr) {
184 if (meta_active) {
186 }
187 copier.begin(out_decoding, *p_input_stream);
188 timeout = millis() + p_source->timeoutAutoNext();
189 active = isActive;
190 result = true;
191 } else {
192 LOGW("-> begin: no data found");
193 active = false;
194 result = false;
195 }
196 } else {
197 LOGW("-> begin: no stream selected");
198 active = isActive;
199 result = false;
200 }
201 return result;
202 }
203
204 void end() {
205 TRACED();
206 active = false;
207 out_decoding.end();
208 meta_out.end();
209 // remove any data in the decoder
210 if (p_decoder != nullptr) {
211 LOGI("reset codec");
212 p_decoder->end();
213 p_decoder->begin();
214 }
215 }
216
218 AudioSource &audioSource() { return *p_source; }
219
221 void setAudioSource(AudioSource &source) { this->p_source = &source; }
222
224 void setDecoder(AudioDecoder &decoder) {
225 this->p_decoder = &decoder;
226 out_decoding.setDecoder(p_decoder);
227 }
228
231 this->p_final_notify = notify;
232 // notification for audio configuration
233 if (p_decoder != nullptr) {
234 p_decoder->addNotifyAudioChange(*this);
235 }
236 }
237
239 void setAudioInfo(AudioInfo info) override {
240 TRACED();
241 LOGI("sample_rate: %d", (int)info.sample_rate);
242 LOGI("bits_per_sample: %d", (int)info.bits_per_sample);
243 LOGI("channels: %d", (int)info.channels);
244 this->info = info;
245 // notifiy volume
246 volume_out.setAudioInfo(info);
247 fade.setAudioInfo(info);
248 // notifiy final ouput: e.g. i2s
249 if (p_final_print != nullptr) p_final_print->setAudioInfo(info);
250 if (p_final_stream != nullptr) p_final_stream->setAudioInfo(info);
251 if (p_final_notify != nullptr) p_final_notify->setAudioInfo(info);
252 };
253
254 AudioInfo audioInfo() override { return info; }
255
257 void play() {
258 TRACED();
259 setActive(true);
260 }
261
265 bool playPath(const char *path) {
266 TRACED();
267 if (!setPath(path)) {
268 LOGW("Could not open file: %s", path);
269 return false;
270 }
271
272 LOGI("Playing %s", path);
273 // start if inactive
274 play();
275 // process all data
276 copyAll();
277
278 LOGI("%s has finished playing", path);
279 return true;
280 }
281
283 bool playFile(const char *path) { return playPath(path); }
284
285
287 void stop() {
288 TRACED();
289 setActive(false);
290 }
291
294 bool next(int offset = 1) {
295 TRACED();
296 writeEnd();
297 stream_increment = offset >= 0 ? 1 : -1;
298 active = setStream(p_source->nextStream(offset));
299 return active;
300 }
301
303 bool setIndex(int idx) {
304 TRACED();
305 writeEnd();
306 stream_increment = 1;
307 active = setStream(p_source->selectStream(idx));
308 return active;
309 }
310
312 bool setPath(const char *path) {
313 TRACED();
314 writeEnd();
315 stream_increment = 1;
316 active = setStream(p_source->selectStream(path));
317 return active;
318 }
319
321 bool previous(int offset = 1) {
322 TRACED();
323 writeEnd();
324 stream_increment = -1;
325 active = setStream(p_source->previousStream(abs(offset)));
326 return active;
327 }
328
330 bool setStream(Stream *input) {
331 end();
332 out_decoding.begin();
333 p_input_stream = input;
334 if (p_input_stream != nullptr) {
335 LOGD("open selected stream");
336 meta_out.begin();
337 copier.begin(out_decoding, *p_input_stream);
338 }
339 // execute callback if defined
340 if (on_stream_change_callback != nullptr)
341 on_stream_change_callback(p_input_stream, p_reference);
342 return p_input_stream != nullptr;
343 }
344
346 Stream *getStream() { return p_input_stream; }
347
349 bool isActive() { return active; }
350
352 operator bool() { return isActive(); }
353
355 void setActive(bool isActive) {
356 if (is_auto_fade) {
357 if (isActive) {
358 fade.setFadeInActive(true);
359 } else {
360 fade.setFadeOutActive(true);
361 copier.copy();
362 writeSilence(2048);
363 }
364 }
365 active = isActive;
366 }
367
369 bool setVolume(float volume) override {
370 bool result = true;
371 if (volume >= 0.0f && volume <= 1.0f) {
372 if (abs(volume - current_volume) > 0.01f) {
373 LOGI("setVolume(%f)", volume);
374 volume_out.setVolume(volume);
375 current_volume = volume;
376 }
377 } else {
378 LOGE("setVolume value '%f' out of range (0.0 -1.0)", volume);
379 result = false;
380 }
381 return result;
382 }
383
385 float volume() override { return current_volume; }
386
390 void setAutoNext(bool next) { autonext = next; }
391
393 void setDelayIfOutputFull(int delayMs) { delay_if_full = delayMs; }
394
397 size_t copy() { return copy(copier.bufferSize()); }
398
400 size_t copyAll() {
401 size_t result = 0;
402 size_t step = copy();
403 while (step > 0) {
404 result += step;
405 step = copy();
406 }
407 return result;
408 }
409
412 size_t copy(size_t bytes) {
413 size_t result = 0;
414 if (active) {
415 TRACED();
416 if (delay_if_full != 0 && ((p_final_print != nullptr &&
417 p_final_print->availableForWrite() == 0) ||
418 (p_final_stream != nullptr &&
419 p_final_stream->availableForWrite() == 0))) {
420 // not ready to do anything - so we wait a bit
421 delay(delay_if_full);
422 return 0;
423 }
424 // handle sound
425 result = copier.copyBytes(bytes);
426 if (result > 0 || timeout == 0) {
427 // reset timeout if we had any data
428 timeout = millis() + p_source->timeoutAutoNext();
429 }
430 // move to next stream after timeout
431 moveToNextFileOnTimeout();
432
433 // return silence when there was no data
434 if (result < bytes && silence_on_inactive) {
435 writeSilence(bytes - result);
436 }
437
438 } else {
439 // e.g. A2DP should still receive data to keep the connection open
440 if (silence_on_inactive) {
441 writeSilence(bytes);
442 }
443 }
444 return result;
445 }
446
448 void setVolumeControl(VolumeControl &vc) { volume_out.setVolumeControl(vc); }
449
452 StreamCopy &getStreamCopy() { return copier; }
453
456 void setSilenceOnInactive(bool active) { silence_on_inactive = active; }
457
459 bool isSilenceOnInactive() { return silence_on_inactive; }
460
462 void writeSilence(size_t bytes) {
463 TRACEI();
464 if (p_final_print != nullptr) {
465 p_final_print->writeSilence(bytes);
466 } else if (p_final_stream != nullptr) {
467 p_final_stream->writeSilence(bytes);
468 }
469 }
470
471 // /// Provides the Print object to which we send the decoding result
472 // Print *getVolumeOutput() { return &volume_out; }
473
475 VolumeStream &getVolumeStream() { return volume_out; }
476
479 void setAutoFade(bool active) { is_auto_fade = active; }
480
481 bool isAutoFade() { return is_auto_fade; }
482
484 void setMetaDataSize(int size) { meta_out.resize(size); }
485
487 void setReference(void *ref) { p_reference = ref; }
488
490 void setMetadataCallback(void (*callback)(MetaDataType type, const char *str,
491 int len),
492 ID3TypeSelection sel = SELECT_ID3) {
493 TRACEI();
494 // setup metadata.
495 if (p_source->setMetadataCallback(callback)) {
496 // metadata is handled by source
497 LOGI("Using ICY Metadata");
498 meta_active = false;
499 } else {
500 // metadata is handled here
501 meta_out.setCallback(callback);
502 meta_out.setFilter(sel);
503 meta_active = true;
504 }
505 }
506
508 void setOnStreamChangeCallback(void (*callback)(Stream *stream_ptr,
509 void *reference)) {
510 on_stream_change_callback = callback;
511 if (p_input_stream!=nullptr) callback(p_input_stream, p_reference);
512 }
513
514 protected:
515 bool active = false;
516 bool autonext = true;
517 bool silence_on_inactive = false;
518 AudioSource *p_source = nullptr;
519 VolumeStream volume_out; // Volume control
520 FadeStream fade; // Phase in / Phase Out to avoid popping noise
521 MetaDataID3 meta_out; // Metadata parser
522 EncodedAudioOutput out_decoding; // Decoding stream
523 CopyDecoder no_decoder{true};
524 AudioDecoder *p_decoder = &no_decoder;
525 Stream *p_input_stream = nullptr;
526 AudioOutput *p_final_print = nullptr;
527 AudioStream *p_final_stream = nullptr;
528 AudioInfoSupport *p_final_notify = nullptr;
529 StreamCopy copier; // copies sound into i2s
530 AudioInfo info;
531 bool meta_active = false;
532 uint32_t timeout = 0;
533 int stream_increment = 1; // +1 moves forward; -1 moves backward
534 float current_volume = -1.0f; // illegal value which will trigger an update
535 int delay_if_full = 100;
536 bool is_auto_fade = true;
537 void *p_reference = nullptr;
538 void (*on_stream_change_callback)(Stream *stream_ptr,
539 void *reference) = nullptr;
540
541 void setupFade() {
542 if (p_final_print != nullptr) {
543 fade.setAudioInfo(p_final_print->audioInfo());
544 } else if (p_final_stream != nullptr) {
545 fade.setAudioInfo(p_final_stream->audioInfo());
546 }
547 }
548
549 void moveToNextFileOnTimeout() {
550 if (p_final_stream != nullptr && p_final_stream->availableForWrite() == 0)
551 return;
552 if (p_input_stream == nullptr || millis() > timeout) {
553 if (is_auto_fade) fade.setFadeInActive(true);
554 if (autonext) {
555 LOGI("-> timeout - moving by %d", stream_increment);
556 // open next stream
557 if (!next(stream_increment)) {
558 LOGD("stream is null");
559 }
560 } else {
561 active = false;
562 }
563 timeout = millis() + p_source->timeoutAutoNext();
564 }
565 }
566
567 void writeEnd() {
568 // end silently
569 TRACEI();
570 if (is_auto_fade) {
571 fade.setFadeOutActive(true);
572 copier.copy();
573 // start by fading in
574 fade.setFadeInActive(true);
575 }
576 // restart the decoder to make sure it does not contain any audio when we
577 // continue
578 p_decoder->begin();
579 }
580
582 static void decodeMetaData(void *obj, void *data, size_t len) {
583 LOGD("%s, %zu", LOG_METHOD, len);
584 AudioPlayer *p = (AudioPlayer *)obj;
585 if (p->meta_active) {
586 p->meta_out.write((const uint8_t *)data, len);
587 }
588 }
589};
590
591} // namespace audio_tools
Decoding of encoded audio into PCM data.
Definition AudioCodecsBase.h:18
virtual bool isResultPCM()
Returns true to indicate that the decoding result is PCM data.
Definition AudioCodecsBase.h:53
virtual void addNotifyAudioChange(AudioInfoSupport &bi)
Adds target to be notified about audio changes.
Definition AudioTypes.h:151
Supports changes to the sampling rate, bits and channels.
Definition AudioTypes.h:133
virtual void setAudioInfo(AudioInfo info)=0
Defines the input AudioInfo.
Abstract Audio Ouptut class.
Definition AudioOutput.h:22
virtual void setAudioInfo(AudioInfo newInfo) override
Defines the input AudioInfo.
Definition AudioOutput.h:46
virtual void writeSilence(size_t len)
Definition AudioOutput.h:63
Implements a simple audio player which supports the following commands:
Definition AudioPlayer.h:38
static void decodeMetaData(void *obj, void *data, size_t len)
Callback implementation which writes to metadata.
Definition AudioPlayer.h:582
void setAudioSource(AudioSource &source)
(Re)defines the audio source
Definition AudioPlayer.h:221
void writeSilence(size_t bytes)
Sends the requested bytes as 0 values to the output.
Definition AudioPlayer.h:462
AudioPlayer(AudioSource &source, AudioStream &output, AudioDecoder &decoder)
Construct a new Audio Player object. The processing chain is AudioSource -> Stream-copy -> EncodedAud...
Definition AudioPlayer.h:89
AudioSource & audioSource()
Provides the actual audio source.
Definition AudioPlayer.h:218
size_t copy(size_t bytes)
Definition AudioPlayer.h:412
size_t copyAll()
Copies all the data.
Definition AudioPlayer.h:400
void setSilenceOnInactive(bool active)
Definition AudioPlayer.h:456
bool isSilenceOnInactive()
Checks if silence_on_inactive has been activated (default false)
Definition AudioPlayer.h:459
void setOnStreamChangeCallback(void(*callback)(Stream *stream_ptr, void *reference))
Defines a callback that is called when the stream is changed.
Definition AudioPlayer.h:508
void setDelayIfOutputFull(int delayMs)
Defines the wait time in ms if the target output is full.
Definition AudioPlayer.h:393
void setMetaDataSize(int size)
Change the default ID3 max metadata size (256)
Definition AudioPlayer.h:484
bool setStream(Stream *input)
start selected input stream
Definition AudioPlayer.h:330
void setDecoder(AudioDecoder &decoder)
(Re)defines the decoder
Definition AudioPlayer.h:224
StreamCopy & getStreamCopy()
Definition AudioPlayer.h:452
bool playFile(const char *path)
Obsolete: use PlayPath!
Definition AudioPlayer.h:283
bool setVolume(float volume) override
sets the volume - values need to be between 0.0 and 1.0
Definition AudioPlayer.h:369
Stream * getStream()
Provides the actual stream (=e.g.file)
Definition AudioPlayer.h:346
void play()
starts / resumes the playing after calling stop(): same as setActive(true)
Definition AudioPlayer.h:257
bool next(int offset=1)
Definition AudioPlayer.h:294
float volume() override
Determines the actual volume.
Definition AudioPlayer.h:385
bool playPath(const char *path)
Definition AudioPlayer.h:265
void addNotifyAudioChange(AudioInfoSupport *notify)
(Re)defines the notify
Definition AudioPlayer.h:230
void stop()
halts the playing: same as setActive(false)
Definition AudioPlayer.h:287
void setAutoNext(bool next)
Definition AudioPlayer.h:390
void setReference(void *ref)
this is used to set the reference for the stream change callback
Definition AudioPlayer.h:487
AudioPlayer()
Default constructor.
Definition AudioPlayer.h:41
void setAutoFade(bool active)
Definition AudioPlayer.h:479
void setMetadataCallback(void(*callback)(MetaDataType type, const char *str, int len), ID3TypeSelection sel=SELECT_ID3)
Defines the medatadata callback.
Definition AudioPlayer.h:490
bool isActive()
determines if the player is active
Definition AudioPlayer.h:349
bool previous(int offset=1)
moves to previous file
Definition AudioPlayer.h:321
VolumeStream & getVolumeStream()
Provides the reference to the volume stream.
Definition AudioPlayer.h:475
bool setPath(const char *path)
Moves to the selected file w/o updating the actual file position.
Definition AudioPlayer.h:312
bool begin(int index=0, bool isActive=true)
Definition AudioPlayer.h:149
void setAudioInfo(AudioInfo info) override
Updates the audio info in the related objects.
Definition AudioPlayer.h:239
void setActive(bool isActive)
The same like start() / stop()
Definition AudioPlayer.h:355
void setBufferSize(int size)
Defines the number of bytes used by the copier.
Definition AudioPlayer.h:145
size_t copy()
Definition AudioPlayer.h:397
AudioInfo audioInfo() override
provides the actual input AudioInfo
Definition AudioPlayer.h:254
bool setIndex(int idx)
moves to the selected file position
Definition AudioPlayer.h:303
AudioPlayer(AudioSource &source, AudioOutput &output, AudioDecoder &decoder)
Construct a new Audio Player object. The processing chain is AudioSource -> Stream-copy -> EncodedAud...
Definition AudioPlayer.h:52
void setVolumeControl(VolumeControl &vc)
Change the VolumeControl implementation.
Definition AudioPlayer.h:448
AudioPlayer(AudioSource &source, Print &output, AudioDecoder &decoder, AudioInfoSupport *notify=nullptr)
Construct a new Audio Player object. The processing chain is AudioSource -> Stream-copy -> EncodedAud...
Definition AudioPlayer.h:71
Abstract Audio Data Source for the AudioPlayer which is used by the Audio Players.
Definition AudioSource.h:16
virtual Stream * selectStream(int index)
Definition AudioSource.h:29
virtual Stream * previousStream(int offset)
Returns previous audio stream.
Definition AudioSource.h:25
virtual bool isAutoNext()
Returns default setting go to the next.
Definition AudioSource.h:63
virtual Stream * nextStream(int offset)=0
Returns next audio stream.
virtual int timeoutAutoNext()
Provides the timeout which is triggering to move to the next stream.
Definition AudioSource.h:50
virtual bool begin()=0
Reset actual stream and move to root.
Base class for all Audio Streams. It support the boolean operator to test if the object is ready with...
Definition BaseStream.h:122
virtual void setAudioInfo(AudioInfo newInfo) override
Defines the input AudioInfo.
Definition BaseStream.h:130
virtual void writeSilence(size_t len)
Writes len bytes of silence (=0).
Definition BaseStream.h:159
Dummy Decoder which just copies the provided data to the output. You can define if it is PCM data.
Definition CodecCopy.h:18
A more natural Print class to process encoded data (aac, wav, mp3...). Just define the output and the...
Definition AudioEncoded.h:21
void end() override
Ends the processing.
Definition AudioEncoded.h:183
bool begin() override
Starts the processing - sets the status to active.
Definition AudioEncoded.h:155
void setOutput(Print *outputStream)
Defines the output.
Definition AudioEncoded.h:104
Stream which can be used to manage fade in and fade out. Before you read or write data you need to ca...
Definition Fade.h:240
void setOutput(Print &out) override
Defines/Changes the output target.
Definition Fade.h:251
void setAudioInfo(AudioInfo info) override
Defines the input AudioInfo.
Definition Fade.h:267
Simple ID3 Meta Data Parser which supports ID3 V1 and V2 and implements the Stream interface....
Definition MetaDataID3.h:569
virtual size_t write(const uint8_t *data, size_t len)
Provide tha audio data to the API to parse for Meta Data.
Definition MetaDataID3.h:601
void resize(int size)
Defines the ID3V3 result buffer size (default is 256);.
Definition MetaDataID3.h:611
Definition NoArduino.h:62
size_t copyBytes(size_t bytes)
copies the inicated number of bytes from the source to the destination and returns the processed numb...
Definition StreamCopy.h:107
void resize(int len)
resizes the copy buffer
Definition StreamCopy.h:308
void setCallbackOnWrite(void(*onWrite)(void *obj, void *buffer, size_t len), void *obj)
Defines a callback that is notified with the wirtten data.
Definition StreamCopy.h:266
void begin()
(Re)starts the processing
Definition StreamCopy.h:50
int bufferSize()
Provides the buffer size.
Definition StreamCopy.h:283
size_t copy()
copies the data from the source to the destination and returns the processed number of bytes
Definition StreamCopy.h:95
Definition NoArduino.h:142
Abstract class for handling of the linear input volume to determine the multiplication factor which s...
Definition VolumeControl.h:19
Adjust the volume of the related input or output: To work properly the class needs to know the bits p...
Definition VolumeStream.h:34
void setOutput(Print &out) override
Defines/Changes the output target.
Definition VolumeStream.h:70
bool setVolume(float vol) override
Defines the volume for all channels: needs to be in the range of 0 to 1.0 (if allow boost has not bee...
Definition VolumeStream.h:181
void setAudioInfo(AudioInfo cfg) override
Detines the Audio info - The bits_per_sample are critical to work properly!
Definition VolumeStream.h:165
void setVolumeControl(VolumeControl &vc)
Defines the volume control logic.
Definition VolumeStream.h:122
Supports the setting and getting of the volume.
Definition AudioTypes.h:189
ID3TypeSelection
Enum to filter by type of metadata.
Definition AbstractMetaData.h:8
MetaDataType
Type of meta info.
Definition AbstractMetaData.h:11
StreamCopyT< uint8_t > StreamCopy
We provide the typeless StreamCopy.
Definition StreamCopy.h:433
Generic Implementation of sound input and output for desktop environments using portaudio.
Definition AudioCodecsBase.h:10
uint32_t millis()
Returns the milliseconds since the start.
Definition Time.h:12
Basic Audio information which drives e.g. I2S.
Definition AudioTypes.h:53
sample_rate_t sample_rate
Sample Rate: e.g 44100.
Definition AudioTypes.h:55
uint16_t channels
Number of channels: 2=stereo, 1=mono.
Definition AudioTypes.h:57
uint8_t bits_per_sample
Number of bits per sample (int16_t = 16 bits)
Definition AudioTypes.h:59