### Playing a PROGMEM MP3 example Source: https://github.com/earlephilhower/esp8266audio/blob/master/_autodocs/api-reference/AudioFileSourceMemory.md Demonstrates initializing an AudioFileSourcePROGMEM with a flash-resident array and starting an MP3 generator. ```c #include "AudioFileSourcePROGMEM.h" #include "AudioGeneratorMP3.h" #include "AudioOutputI2SNoDAC.h" #include "myfile.h" // contains: const unsigned char myfile[] PROGMEM = { ... }; AudioFileSourcePROGMEM *file = new AudioFileSourcePROGMEM(myfile, sizeof(myfile)); AudioGeneratorMP3 *mp3 = new AudioGeneratorMP3(); AudioOutputI2SNoDAC *out = new AudioOutputI2SNoDAC(); mp3->begin(file, out); ``` -------------------------------- ### MOD Playback with Tuned Buffer and Stereo Source: https://github.com/earlephilhower/esp8266audio/blob/master/_autodocs/api-reference/AudioGeneratorMOD.md Example demonstrating how to configure the MOD player with custom sample rate, buffer size, stereo separation, and PAL timing before starting playback. ```c #include "AudioFileSourcePROGMEM.h" #include "AudioGeneratorMOD.h" #include "AudioOutputI2SNoDAC.h" AudioFileSourcePROGMEM *file = new AudioFileSourcePROGMEM(song, sizeof(song)); AudioGeneratorMOD *mod = new AudioGeneratorMOD(); AudioOutputI2SNoDAC *out = new AudioOutputI2SNoDAC(); mod->SetSampleRate(22050); // halve CPU pressure mod->SetBufferSize(4 * 1024); // less RAM per channel mod->SetStereoSeparation(48); // narrower stereo mod->SetPAL(true); // European Amiga timing mod->begin(file, out); void loop() { if (mod->isRunning() && !mod->loop()) { mod->stop(); } } ``` -------------------------------- ### Example conversion with Scratch2010.sf2 Source: https://github.com/earlephilhower/esp8266audio/blob/master/src/libtinysoundfont/README.ESP8266Audio.md Example invocation of the converter using Scratch2010.sf2 as input and scratch2010.h as output. Note the stray '#' in the command as shown in the source. ```bash $ ./# dump-linux-x86_64 Scratch2010.sf2 scratch2010.h ``` -------------------------------- ### Example - Basic wiring into a generator Source: https://github.com/earlephilhower/esp8266audio/blob/master/_autodocs/api-reference/AudioFileSource.md Shows how to create an AudioFileSourceSPIFFS, AudioGeneratorWAV, and AudioOutputI2S, open a file, and begin playback. ```APIDOC ## Example - Basic wiring into a generator ### Description Shows how to create an AudioFileSourceSPIFFS, AudioGeneratorWAV, and AudioOutputI2S, open a file, and begin playback. ### Code ```c #include "AudioFileSourceSPIFFS.h" #include "AudioGeneratorWAV.h" #include "AudioOutputI2S.h" AudioFileSourceSPIFFS *file = new AudioFileSourceSPIFFS("/snd/tone.wav"); AudioGeneratorWAV *wav = new AudioGeneratorWAV(); AudioOutputI2S *out = new AudioOutputI2S(); if (!file->open("/snd/tone.wav")) { // open() already returns false; base contract requires the caller to check. } wav->begin(file, out); // begin() itself verifies isOpen() ``` ``` -------------------------------- ### Chaining say() calls for sequential speech Source: https://github.com/earlephilhower/esp8266audio/blob/master/_autodocs/api-reference/AudioGeneratorTalkie.md Example showing how to chain multiple say() calls to build a sentence. Each say() waits for the previous phrase to finish before starting. ```cpp talkie->say(spTHE, sizeof(spTHE)); talkie->say(spTIME, sizeof(spTIME)); talkie->say(spIS, sizeof(spIS)); ``` -------------------------------- ### AudioOutputFilterDecimate Usage Example Source: https://github.com/earlephilhower/esp8266audio/blob/master/_autodocs/api-reference/AudioOutputMixer.md Example showing how to initialize a 2x downsample filter with a 31-tap windowed-sinc kernel. ```c // 2x downsample with a 31-tap windowed-sinc kernel static const int16_t fir31[31] = { /* ... */ }; AudioOutputFilterDecimate *ds = new AudioOutputFilterDecimate(31, fir31, 1, 2, dac); generator->begin(file, ds); ``` -------------------------------- ### virtual bool begin(AudioFileSource *source, AudioOutput *output) Source: https://github.com/earlephilhower/esp8266audio/blob/master/_autodocs/api-reference/AudioGenerator.md Starts decoding from the given source and output. Returns true when decoding started, false on invalid/missing source, unopen file, output misconfiguration, or out-of-memory. ```APIDOC ## virtual bool begin(AudioFileSource *source, AudioOutput *output) ### Description Starts decoding from the given source and output. Subclasses configure the output (SetChannels(2), SetRate(...), begin()) before returning true. Returns false on invalid/missing source, unopen file, output misconfiguration, or out-of-memory. ### Method begin ### Signature ```c virtual bool begin(AudioFileSource *source, AudioOutput *output) { (void)source; (void)output; return false; }; ``` ### Parameters - **source** (AudioFileSource *) - Required - Input; must be open (isOpen()) when the subclass implementation runs. - **output** (AudioOutput *) - Required - Destination renderer. ### Returns - **bool** - true when decoding started, false on failure. ``` -------------------------------- ### Asynchronous speech example with AudioGeneratorTalkie Source: https://github.com/earlephilhower/esp8266audio/blob/master/_autodocs/api-reference/AudioGeneratorTalkie.md Example that starts speech asynchronously and drives the generator from loop() until isRunning() returns false. ```cpp AudioGeneratorTalkie *talkie = new AudioGeneratorTalkie(); talkie->begin(NULL, out); talkie->say(spTIME, sizeof(spTIME), true); // returns immediately void loop() { if (talkie->isRunning()) { if (!talkie->loop()) talkie->stop(); } } ``` -------------------------------- ### begin(AudioFileSource *source, AudioOutput *output) Source: https://github.com/earlephilhower/esp8266audio/blob/master/_autodocs/api-reference/AudioGeneratorMOD.md Starts playback of a MOD file from the given source, outputting to the given output. Loads the header, allocates fat buffers, and initializes the output. ```APIDOC ## begin(AudioFileSource *source, AudioOutput *output) ### Description Starts playback of a MOD file from the given source, outputting to the given output. Loads the header, allocates fat buffers, and initializes the output. ### Method begin ### Syntax ```c virtual bool begin(AudioFileSource *source, AudioOutput *output) override; ``` ### Parameters - **source** (AudioFileSource*) - Required - Pointer to the audio file source (e.g., AudioFileSourcePROGMEM). - **output** (AudioOutput*) - Required - Pointer to the audio output (e.g., AudioOutputI2SNoDAC). ### Returns - **bool** - `true` on success, `false` on failure. ### Failure Conditions - If `Mod.numberOfChannels > CHANNELS`, logs to `audioLogger` and returns `false`. - If `calloc()` of fat buffers fails, returns `false`. - If `output->SetRate/SetChannels/begin` fails, returns `false`. ### Notes - Must be called after all `Set*()` configuration methods. - Internally calls `output->SetRate(sampleRate)`, `SetChannels(2)`, `begin()`, and starts the track. ``` -------------------------------- ### Example: pushing a file source into WiFiClient-style consumers Source: https://github.com/earlephilhower/esp8266audio/blob/master/_autodocs/api-reference/AudioFileSourceMisc.md Shows how to wrap an AudioFileSourcePROGMEM with AudioFileStream and read bytes until -1, handing them to any Arduino Stream consumer. ```c #include "AudioFileSourcePROGMEM.h" #include "AudioFileStream.h" AudioFileSourcePROGMEM *f = new AudioFileSourcePROGMEM(data, len); AudioFileStream stream(f, len); int b; while ((b = stream.read()) != -1) { // hand bytes to any Arduino Stream consumer } ``` -------------------------------- ### Example - Registering status/metadata callbacks on a source Source: https://github.com/earlephilhower/esp8266audio/blob/master/_autodocs/api-reference/AudioFileSource.md Shows how to register a status callback on an AudioFileSourceHTTPStream and open a stream. ```APIDOC ## Example - Registering status/metadata callbacks on a source ### Description Shows how to register a status callback on an AudioFileSourceHTTPStream and open a stream. ### Code ```c void statusCb(void *data, int code, const char *string) { Serial.printf("status %d: %s\n", code, string); // string may be PSTR } AudioFileSourceHTTPStream *src = new AudioFileSourceHTTPStream(); src->RegisterStatusCB(statusCb, NULL); if (!src->open("http://example.com/stream.mp3")) { /* STATUS_HTTPFAIL was raised */ } ``` ``` -------------------------------- ### Failed Configuration Handling Source: https://github.com/earlephilhower/esp8266audio/blob/master/_autodocs/api-reference/AudioGeneratorMOD.md Example showing how to handle rejected configuration attempts when parameters are out of the allowed range. ```c if (!mod->SetSampleRate(0)) { // 0 is out of the 1..96000 range Serial.println("SetSampleRate rejected"); } if (!mod->SetStereoSeparation(100)) { Serial.println("stereo separation must be 0..64"); } ``` -------------------------------- ### Default Heap-based MP3 Playback Source: https://github.com/earlephilhower/esp8266audio/blob/master/_autodocs/api-reference/AudioGeneratorMP3.md Example demonstrating how to initialize and run an MP3 generator using default heap allocation. ```c #include "AudioFileSourceSPIFFS.h" #include "AudioGeneratorMP3.h" #include "AudioOutputI2SNoDAC.h" AudioGeneratorMP3 *mp3 = new AudioGeneratorMP3(); AudioFileSourceSPIFFS *file = new AudioFileSourceSPIFFS("/jamonit.mp3"); AudioOutputI2SNoDAC *out = new AudioOutputI2SNoDAC(); mp3->begin(file, out); void loop() { if (mp3->isRunning()) { if (!mp3->loop()) mp3->stop(); } } ``` -------------------------------- ### AudioOutputNull Decode Speed Benchmark Example Source: https://github.com/earlephilhower/esp8266audio/blob/master/_autodocs/api-reference/AudioOutputMixer.md Example demonstrating how to use AudioOutputNull to benchmark decoding speed. ```c AudioOutputNull *nullOut = new AudioOutputNull(); AudioGeneratorMP3 *mp3 = new AudioGeneratorMP3(); mp3->begin(file, nullOut); while (mp3->loop()) { /* as fast as possible */ } mp3->stop(); Serial.printf("decoded %d samples in %lu ms\n", nullOut->GetSamples(), nullOut->GetMilliseconds()); ``` -------------------------------- ### Stereo pair example Source: https://github.com/earlephilhower/esp8266audio/blob/master/_autodocs/api-reference/AudioFileSourceMemory.md Demonstrates setting up a stereo audio source with two distinct generator functions. ```c AudioFileSourceFunction *file = new AudioFileSourceFunction(8., 2, 44100, 16); bool ok = file->addAudioGenerators( [](const float t) { return 0.25f * sin(TWO_PI * 440.f * t); }, // L: C [](const float t) { return 0.25f * sin(TWO_PI * 550.f * t); } // R: E ); if (!ok) { // Wrong function count for 2 channels — file->addAudioGenerators() returned false } ``` -------------------------------- ### TOSLINK LED blaster example Source: https://github.com/earlephilhower/esp8266audio/blob/master/_autodocs/api-reference/AudioOutputSPDIF.md Example of using AudioOutputSPDIF with a FLAC generator and SD file source. It creates the output on GPIO27, sets deeper DMA buffers (16, 1024) to handle BMC drain, and plays a FLAC file in the loop. ```c #include "AudioOutputSPDIF.h" #include "AudioGeneratorFLAC.h" #include "AudioFileSourceSD.h" AudioOutputSPDIF *out = new AudioOutputSPDIF(27); // GPIO27 -> LED + TOSLINK out->SetBuffers(16, 1024); // deeper DMA for BMC drain AudioGeneratorFLAC *flac = new AudioGeneratorFLAC(); flac->begin(new AudioFileSourceSD("/music/trk.flac"), out); void loop() { if (flac->isRunning() && !flac->loop()) flac->stop(); } ``` -------------------------------- ### Example — begin() failure handling Source: https://github.com/earlephilhower/esp8266audio/blob/master/_autodocs/api-reference/AudioGenerator.md Shows how to check begin() return value and clean up on failure. Many decoders log the specific rejection reason to audioLogger; set audioLogger = &Serial; to see them. ```c AudioFileSourceSPIFFS *file = new AudioFileSourceSPIFFS("/missing.mp3"); AudioGeneratorMP3 *mp3 = new AudioGeneratorMP3(); AudioOutputI2SNoDAC *out = new AudioOutputI2SNoDAC(); if (!mp3->begin(file, out)) { Serial.println("begin failed: file not open or output misconfigured"); delete mp3; // clean up } ``` -------------------------------- ### AudioOutputPDM usage example Source: https://github.com/earlephilhower/esp8266audio/blob/master/_autodocs/api-reference/AudioOutputI2S.md Minimal example showing how to use AudioOutputPDM with AudioGeneratorWAV. Creates a PDM output on GPIO10 and attaches it to a WAV generator. Requires including the headers and having a file handle. ```c #include "AudioOutputPDM.h" #include "AudioGeneratorWAV.h" AudioOutputPDM *out = new AudioOutputPDM(10); // PDM on GPIO10 AudioGeneratorWAV *wav = new AudioGeneratorWAV(); wav->begin(file, out); ``` -------------------------------- ### Example - with manual cleanup Source: https://github.com/earlephilhower/esp8266audio/blob/master/_autodocs/api-reference/AudioGeneratorOpus.md Example code showing manual cleanup, since stop() does not close the source for Opus. ```APIDOC ## Example - with manual cleanup ### Description Example code showing manual cleanup, since stop() does not close the source for Opus. ### Code ```c AudioGeneratorOpus *opus = new AudioGeneratorOpus(); if (opus->begin(file, out)) { while (opus->loop()) { /* pump */ } } opus->stop(); file->close(); // stop() does not close the source for Opus ``` ``` -------------------------------- ### AudioOutputInternalDAC usage example Source: https://github.com/earlephilhower/esp8266audio/blob/master/_autodocs/api-reference/AudioOutputI2S.md Minimal example showing how to use AudioOutputInternalDAC. Creates an output with a buffer size of 512, sets a 0.7 gain, and attaches it to a generator. Requires including the header and having a generator object. ```c #include "AudioOutputInternalDAC.h" AudioOutputInternalDAC *out = new AudioOutputInternalDAC(512); out->SetGain(0.7); generator->begin(file, out); ``` -------------------------------- ### Example: MIDI from PROGMEM with a tsf SoundFont Source: https://github.com/earlephilhower/esp8266audio/blob/master/_autodocs/api-reference/AudioGeneratorMIDI.md Shows how to set up AudioGeneratorMIDI with a SoundFont loaded via tsf_load, a PROGMEM MIDI file source, and I2S output. Includes loop() to keep playback running. ```c #include "AudioFileSourcePROGMEM.h" #include "AudioGeneratorMIDI.h" #include "AudioOutputI2S.h" AudioOutputI2S *dac = new AudioOutputI2S(); dac->SetPinout(0, 1, 2); // any I2S pinout dac->SetGain(0.5); audioLogger = &Serial; tsf *sf2 = tsf_load(&Serial, 0, 0, 1); // or tsf_load_midifile(...); see tsf.h AudioFileSourcePROGMEM *mid = new AudioFileSourcePROGMEM(_mid, sizeof(_mid)); AudioGeneratorMIDI *midi = new AudioGeneratorMIDI(); midi->SetSoundFont(sf2); midi->SetSampleRate(22050); midi->begin(mid, dac); void loop() { if (midi->isRunning()) { if (!midi->loop()) midi->stop(); } } ``` -------------------------------- ### Example — standard main loop Source: https://github.com/earlephilhower/esp8266audio/blob/master/_autodocs/api-reference/AudioGenerator.md Shows the typical usage pattern: create a decoder, call begin() once, then in loop() call gen->loop() while running, and stop when it returns false. ```c AudioGenerator *gen = (AudioGenerator*)new AudioGeneratorMP3(); // ... begin(gen, source, out) ... void loop() { if (gen->isRunning()) { if (!gen->loop()) gen->stop(); } else { delay(1000); } } ``` -------------------------------- ### AudioOutputULP example usage Source: https://github.com/earlephilhower/esp8266audio/blob/master/_autodocs/api-reference/AudioOutputI2S.md Creates an AudioOutputULP instance (stereo by default or mono with argument 1) and passes it to generator->begin with an audio file. ```c #include "AudioOutputULP.h" AudioOutputULP *out = new AudioOutputULP(); // stereo on 25/26 // or: AudioOutputULP *out = new AudioOutputULP(1); // mono DAC1 only generator->begin(file, out); ``` -------------------------------- ### Pre-allocated MP3 with Status Callback Source: https://github.com/earlephilhower/esp8266audio/blob/master/_autodocs/api-reference/AudioGeneratorMP3.md Example showing how to use static RAM allocation for the MP3 generator and register a status callback for error reporting. ```c #include "AudioGeneratorMP3.h" void st(void *d, int code, const char *s) { // code == MAD_ERROR_* (see libmad/mad.h); s = "Decoding error '...' at byte offset N" Serial.printf("MP3 status %d: %s\n", code, s); } static uint8_t mp3mem[AudioGeneratorMP3::preAllocSize()]; AudioGeneratorMP3 *mp3 = new AudioGeneratorMP3(mp3mem, sizeof(mp3mem)); mp3->RegisterStatusCB(st, NULL); if (!mp3->begin(file, out)) { // OOM error in MP3 was logged to audioLogger; preAllocSize() too small } ``` -------------------------------- ### Example — PWM on the Pico Source: https://github.com/earlephilhower/esp8266audio/blob/master/_autodocs/api-reference/AudioOutputSPDIF.md Demonstrates playing a WAV file from LittleFS through AudioOutputPWM at 22.05 kHz on the built-in speaker pin. Requires AudioOutputPWM.h, AudioGeneratorWAV.h, and AudioFileSourceLittleFS.h. ```c #include "AudioOutputPWM.h" #include "AudioGeneratorWAV.h" #include "AudioFileSourceLittleFS.h" AudioOutputPWM *out = new AudioOutputPWM(22050, 0); // 22.05 kHz on built-in speaker pin AudioGeneratorWAV *wav = new AudioGeneratorWAV(); wav->begin(new AudioFileSourceLittleFS("/snd/tone.wav"), out); void loop() { if (wav->isRunning() && !wav->loop()) wav->stop(); } ``` -------------------------------- ### Example — Opus from LittleFS Source: https://github.com/earlephilhower/esp8266audio/blob/master/_autodocs/api-reference/AudioGeneratorOpus.md Shows how to play an Opus file from LittleFS using AudioFileSourceLittleFS, AudioGeneratorOpus, and AudioOutputI2S. Calls begin() and checks for failure, then loops while isRunning() and calls loop(), stopping on failure. ```c #include "AudioFileSourceLittleFS.h" #include "AudioGeneratorOpus.h" #include "AudioOutputI2S.h" AudioFileSourceLittleFS *file = new AudioFileSourceLittleFS("/radio/snd.opus"); AudioGeneratorOpus *opus = new AudioGeneratorOpus(); AudioOutputI2S *out = new AudioOutputI2S(); if (!opus->begin(file, out)) { Serial.println("Opus begin failed"); return; } while (opus->isRunning()) { if (!opus->loop()) opus->stop(); } ``` -------------------------------- ### Single-channel sine sweep example Source: https://github.com/earlephilhower/esp8266audio/blob/master/_autodocs/api-reference/AudioFileSourceMemory.md Demonstrates setting up a mono audio source with a single generator function and playing it via I2S. ```c #include "AudioFileSourceFunction.h" #include "AudioGeneratorWAV.h" #include "AudioOutputI2S.h" AudioFileSourceFunction *file = new AudioFileSourceFunction(8., 1, 44100, 16); file->addAudioGenerators([](const float time) { float v = sin(TWO_PI * 440.f * time); // 440 Hz sine v *= fmod(time, 1.f); // linear decay each second return v * 0.5f; }); AudioGeneratorWAV *wav = new AudioGeneratorWAV(); AudioOutputI2S *out = new AudioOutputI2S(); wav->begin(file, out); // call wav->loop() from your loop() ``` -------------------------------- ### Example — with manual cleanup Source: https://github.com/earlephilhower/esp8266audio/blob/master/_autodocs/api-reference/AudioGeneratorOpus.md Shows manual cleanup after playback. Calls begin(), then loops while loop() returns true, then calls stop() and file->close() because stop() does not close the source for Opus. ```c AudioGeneratorOpus *opus = new AudioGeneratorOpus(); if (opus->begin(file, out)) { while (opus->loop()) { /* pump */ } } opus->stop(); file->close(); // stop() does not close the source for Opus ``` -------------------------------- ### AudioFileSourceHTTPStream open method Source: https://github.com/earlephilhower/esp8266audio/blob/master/_autodocs/api-reference/AudioFileSourceStreaming.md Opens an HTTP(S) URL. Calls http.begin(client, url), http.setReuse(true), and on non-ESP32 setFollowRedirects(HTTPC_FORCE_FOLLOW_REDIRECTS), then http.GET(). Returns false and raises STATUS_HTTPFAIL if the GET status is not HTTP_CODE_OK. ```c virtual bool open(const char *url) override; ``` -------------------------------- ### Example - pre-check the source Source: https://github.com/earlephilhower/esp8266audio/blob/master/_autodocs/api-reference/AudioGeneratorRTTTL.md Shows how to verify that the source is open and begin() succeeds before playback. If begin fails, prints an error message. Note that begin() expects a valid, open source and frees buff on end. ```c if (!file->isOpen() || !rtttl->begin(file, out)) { // RTTTL begin expects a valid, open source; also frees buff on end Serial.println("RTTTL begin failed"); } ``` -------------------------------- ### begin(AudioFileSource *source, AudioOutput *output) Source: https://github.com/earlephilhower/esp8266audio/blob/master/_autodocs/api-reference/AudioGeneratorRTTTL.md Initializes the player with a file source and output. Copies the whole song text into a RAM buffer, parses the header, and configures the output rate. ```APIDOC ## begin(AudioFileSource *source, AudioOutput *output) ### Description Initializes the player with a file source and output. Copies the whole song text into a RAM buffer, parses the header, and configures the output rate. ### Method begin ### Parameters - **source** (AudioFileSource*) - Required - The audio file source to read the RTTTL data from. - **output** (AudioOutput*) - Required - The audio output to send the generated audio to. ### Returns bool - true if initialization succeeded, false otherwise. ### Example ```c rtttl->begin(file, out); ``` ``` -------------------------------- ### begin Source: https://github.com/earlephilhower/esp8266audio/blob/master/_autodocs/api-reference/AudioOutputSPDIF.md Initializes the PWM output hardware. ```APIDOC ## bool begin() ### Description Starts the PWM output and prepares the hardware for audio playback. ### Returns - **bool** - True if successful, false otherwise. ``` -------------------------------- ### Example: capturing format errors Source: https://github.com/earlephilhower/esp8266audio/blob/master/_autodocs/api-reference/AudioGeneratorMIDI.md Registers a status callback to receive MIDI error codes and messages, and checks begin() return value to detect output setup failure. ```c void st(void *d, int code, const char *s) { // code = file byte offset; s = one of the midi_error strings Serial.printf("MIDI error at %d: %s\n", code, s); } midi->RegisterStatusCB(st, NULL); if (!midi->begin(mid, dac)) { Serial.println("MIDI begin failed (output setup)"); } ``` -------------------------------- ### begin(AudioFileSource *mid, AudioOutput *output) Source: https://github.com/earlephilhower/esp8266audio/blob/master/_autodocs/api-reference/AudioGeneratorMIDI.md Starts MIDI playback from the given file source and outputs to the given audio output. Resets track and tonegen state, configures the output, and parses the SMF header. Returns false if any output stage rejects configuration. ```APIDOC ## begin(AudioFileSource *mid, AudioOutput *output) ### Description Starts MIDI playback from the given file source and outputs to the given audio output. Resets track and tonegen state, configures the output, and parses the SMF header. Returns false if any output stage rejects configuration. ### Method begin ### Parameters - **mid** (AudioFileSource *) - Required - Pointer to the MIDI file source. - **output** (AudioOutput *) - Required - Pointer to the audio output. ### Returns - **bool** - true if successful, false if configuration fails. ### Example ```c virtual bool begin(AudioFileSource *mid, AudioOutput *output) override; ``` ``` -------------------------------- ### Example: extracting ID3 tags with AudioFileSourceID3 Source: https://github.com/earlephilhower/esp8266audio/blob/master/_autodocs/api-reference/AudioFileSourceMisc.md Shows how to wrap an HTTP stream with AudioFileSourceID3, register a metadata callback, and play MP3. The callback prints tag types and values; the stream emits "Title", "Performer", "Album", etc., then "eof" before audio starts. ```c #include "AudioFileSourceHTTPStream.h" #include "AudioFileSourceID3.h" #include "AudioGeneratorMP3.h" #include "AudioOutputI2S.h" void meta(void *d, const char *type, bool unicode, const char *str) { Serial.printf("%s = %s\n", type, str); } AudioFileSourceHTTPStream *raw = new AudioFileSourceHTTPStream("http://srv/song.mp3"); AudioFileSourceID3 *file = new AudioFileSourceID3(raw); file->RegisterMetadataCB(meta, NULL); AudioGeneratorMP3 *mp3 = new AudioGeneratorMP3(); AudioOutputI2S *out = new AudioOutputI2S(); mp3->begin(file, out); // Callbacks: "Title", "Performer", "Album", ... then "eof" before the audio starts. ``` -------------------------------- ### AudioOutput::begin Source: https://github.com/earlephilhower/esp8266audio/blob/master/_autodocs/api-reference/AudioOutput.md Initializes the hardware output. Returns true when ready for samples. ```APIDOC ## AudioOutput::begin ### Description Initializes the hardware output. Returns true when ready for samples. ### Method begin ### Signature `virtual bool begin()` ### Parameters None ### Returns - **bool** - `true` if initialization succeeded, `false` otherwise. ### Example ```c if (!out->begin()) { // handle error } ``` ``` -------------------------------- ### AudioOutputFilterBiquad Usage Example Source: https://github.com/earlephilhower/esp8266audio/blob/master/_autodocs/api-reference/AudioOutputMixer.md Example showing how to initialize an AudioOutputFilterBiquad with a low-pass filter and connect it to an I2S output. ```c #include "AudioOutputFilterBiquad.h" AudioOutputI2S *dac = new AudioOutputI2S(); AudioOutputFilterBiquad *lpf = new AudioOutputFilterBiquad( bq_type_lowpass, 2000.0f, 0.707f, 0.0f, dac); generator->begin(file, lpf); // output gets a 2 kHz low-passed mix ``` -------------------------------- ### Example - Opus from LittleFS Source: https://github.com/earlephilhower/esp8266audio/blob/master/_autodocs/api-reference/AudioGeneratorOpus.md Example code showing how to play an Opus file from LittleFS using AudioGeneratorOpus. ```APIDOC ## Example - Opus from LittleFS ### Description Example code showing how to play an Opus file from LittleFS using AudioGeneratorOpus. ### Code ```c #include "AudioFileSourceLittleFS.h" #include "AudioGeneratorOpus.h" #include "AudioOutputI2S.h" AudioFileSourceLittleFS *file = new AudioFileSourceLittleFS("/radio/snd.opus"); AudioGeneratorOpus *opus = new AudioGeneratorOpus(); AudioOutputI2S *out = new AudioOutputI2S(); if (!opus->begin(file, out)) { Serial.println("Opus begin failed"); return; } while (opus->isRunning()) { if (!opus->loop()) opus->stop(); } ``` ``` -------------------------------- ### Initialize and render audio with TinySoundFont Source: https://github.com/earlephilhower/esp8266audio/blob/master/src/libtinysoundfont/README.md This snippet demonstrates the basic workflow of defining the implementation, loading a SoundFont file, setting output parameters, triggering a note, and rendering the audio output. ```c++ #define TSF_IMPLEMENTATION #include "tsf.h" ... tsf* TinySoundFont = tsf_load_filename("soundfont.sf2"); tsf_set_output(TinySoundFont, TSF_MONO, 44100, 0); //sample rate tsf_note_on(TinySoundFont, 0, 60, 1.0f); //preset 0, middle C short HalfSecond[22050]; //synthesize 0.5 seconds tsf_render_short(TinySoundFont, HalfSecond, 22050, 0); ``` -------------------------------- ### AudioOutputSPDIF::begin Source: https://github.com/earlephilhower/esp8266audio/blob/master/_autodocs/api-reference/AudioOutputSPDIF.md Initializes the S/PDIF output and prepares the hardware for audio streaming. ```APIDOC ## AudioOutputSPDIF::begin ### Description Initializes the S/PDIF output, configuring the I2S peripheral and DMA buffers for audio streaming. ### Method begin ### Endpoint virtual bool begin() override; ### Parameters None. ### Request Example ```c out->begin(); ``` ### Response Returns true on success, false on failure. ``` -------------------------------- ### Basic wiring into a generator Source: https://github.com/earlephilhower/esp8266audio/blob/master/_autodocs/api-reference/AudioFileSource.md Shows how to create a file source, generator, and output, then begin playback. The file->open() call returns false on failure and the caller must check; wav->begin() verifies isOpen() itself. ```c #include "AudioFileSourceSPIFFS.h" #include "AudioGeneratorWAV.h" #include "AudioOutputI2S.h" AudioFileSourceSPIFFS *file = new AudioFileSourceSPIFFS("/snd/tone.wav"); AudioGeneratorWAV *wav = new AudioGeneratorWAV(); AudioOutputI2S *out = new AudioOutputI2S(); if (!file->open("/snd/tone.wav")) { // open() already returns false; base contract requires the caller to check. } wav->begin(file, out); // begin() itself verifies isOpen() ``` -------------------------------- ### AudioOutputSPIFFSWAV usage example Source: https://github.com/earlephilhower/esp8266audio/blob/master/_autodocs/api-reference/AudioOutputWAV.md Example usage of AudioOutputSPIFFSWAV: mount SPIFFS, set filename, rate, and channels, then run the generator loop and stop to finalize the RIFF sizes. ```c SPIFFS.begin(true); // format+start AudioOutputSPIFFSWAV *rec = new AudioOutputSPIFFSWAV(); rec->SetFilename("/rec.wav"); rec->SetRate(8000); rec->SetChannels(1); generator->begin(micSource, rec); while (generator->loop()); generator->stop(); // finalize the RIFF sizes ``` -------------------------------- ### Synchronous speech example with AudioGeneratorTalkie Source: https://github.com/earlephilhower/esp8266audio/blob/master/_autodocs/api-reference/AudioGeneratorTalkie.md Example that creates a talkie instance, begins with no file source, and speaks a phrase synchronously. The say() call blocks until the phrase completes. ```cpp #include "AudioGeneratorTalkie.h" #include "AudioOutputI2SNoDAC.h" #include "vocab.h" // exports spHELLO etc.: const uint8_t spHELLO[] PROGMEM = {...}; AudioGeneratorTalkie *talkie = new AudioGeneratorTalkie(); AudioOutputI2SNoDAC *out = new AudioOutputI2SNoDAC(); talkie->begin(NULL, out); // no file source needed talkie->say(spHELLO, sizeof(spHELLO)); // blocks until finished (async=false) ``` -------------------------------- ### Example - ringtone from PROGMEM Source: https://github.com/earlephilhower/esp8266audio/blob/master/_autodocs/api-reference/AudioGeneratorRTTTL.md Complete example showing how to play an RTTTL ringtone stored in PROGMEM using AudioFileSourcePROGMEM, AudioGeneratorRTTTL, and AudioOutputI2SNoDAC. Sets rate to 22050, begins playback, and loops until finished. ```c #include "AudioFileSourcePROGMEM.h" #include "AudioGeneratorRTTTL.h" #include "AudioOutputI2SNoDAC.h" // "Entertainer:b=125,o=5,d=4,8g5,8g#5,..." const char song[] PROGMEM = "Entertainer:b=125,o=5,d=4,8g5,8g#5,8d6,8d#6,8c6,8b5,8a5,8e6,4d6,4b4,..."; AudioFileSourcePROGMEM *file = new AudioFileSourcePROGMEM(song, sizeof(song)); AudioGeneratorRTTTL *rtttl = new AudioGeneratorRTTTL(); AudioOutputI2SNoDAC *out = new AudioOutputI2SNoDAC(); rtttl->SetRate(22050); rtttl->begin(file, out); void loop() { if (rtttl->isRunning()) { if (!rtttl->loop()) rtttl->stop(); } } ``` -------------------------------- ### AudioOutputSerialWAV usage example Source: https://github.com/earlephilhower/esp8266audio/blob/master/_autodocs/api-reference/AudioOutputWAV.md Example usage of AudioOutputSerialWAV: create the output, set rate and channels, then run a generator loop and stop to finalize the WAV header. Capture the serial output to a file on the host. ```c #include "AudioOutputSerialWAV.h" AudioOutputSerialWAV *wavOut = new AudioOutputSerialWAV(); wavOut->SetRate(22050); wavOut->SetChannels(1); generator->begin(file, wavOut); while (generator->loop()); // then capture: miniterm --raw > out.wav generator->stop(); ``` -------------------------------- ### AudioGeneratorFLAC Source: https://github.com/earlephilhower/esp8266audio/blob/master/_autodocs/api-reference/AudioGeneratorFLAC.md Complete API documentation for the AudioGeneratorFLAC class, including constructor, methods, callbacks, and examples. ```APIDOC ## AudioGeneratorFLAC ### Description Decodes Free Lossless Audio Codec (`.flac`) files using a port of libFLAC 1.3.2. Source: `src/AudioGeneratorFLAC.h` (import path: `#include "AudioGeneratorFLAC.h"`). ### Constructor ```c AudioGeneratorFLAC(); virtual ~AudioGeneratorFLAC() override; ``` | Parameter | Type | Required | Default | Description | |-----------|------|----------|---------|-------------| | (none) | — | — | — | Default; the decoder is allocated in `begin()` | ### Methods ```c virtual bool begin(AudioFileSource *source, AudioOutput *output) override; virtual bool loop() override; virtual bool stop() override; virtual bool isRunning() override; ``` `begin()` (`src/AudioGeneratorFLAC.cpp`): 1. Creates a `FLAC__stream_decoder`; on failure returns `false`. 2. Disables MD5 checking: `FLAC__stream_decoder_set_md5_checking(flac, false)`. 3. Initializes the streaming decoder with seven static bounce callbacks bound to `this` (read, seek, tell, length, eof, write, metadata, error). 4. On init failure deletes the decoder and returns `false`. 5. Then configures the output (`SetRate`, `SetChannels`, `begin`) and sets `running = true`. If the source is not open or the decoder cannot be initialized, `begin()` returns `false` (satisfying the pattern used by the other generators). `loop()` drives `FLAC__stream_decoder_process_single()`; decoded frames are converted to interleaved signed 16-bit stereo. Mono is duplicated via `MakeSampleStereo16`. Returns `running`. ### Metadata and error callbacks ```c static char error_cb_str[64]; void error_cb(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status) { (void) decoder; strncpy_P(error_cb_str, FLAC__StreamDecoderErrorStatusString[status], sizeof(AudioGeneratorFLAC::error_cb_str) - 1); cb.st((int)status, error_cb_str); } ``` | Status code | String | Trigger | |-------------|--------|---------| | `(int)status` — the libFLAC `FLAC__StreamDecoderErrorStatus` enum value | `FLAC__StreamDecoderErrorStatusString[status]` (e.g. `"FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC"`, `"FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER"`, `"FLAC__STREAM_DECODER_ERROR_STATUS_FRAME_CRC_MISMATCH"`, `"FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM"`) | libFLAC reports a frame-level loss (lost sync, bad header, CRC mismatch, unparseable stream) | The string is shared static storage (`error_cb_str`, 64 bytes) — copy it out in the callback. The metadata callback currently only logs `"Metadata\n"` via `audioLogger` and does not emit `cb.md()` events, so no ID3-style metadata is surfaced from FLAC. Read callback shortfalls abort the decoding: `FLAC__STREAM_DECODER_READ_STATUS_ABORT` when the file read fails, `END_OF_STREAM` at EOF. The seek callback returns `FLAC__STREAM_DECODER_SEEK_STATUS_ERROR` on failed source seeks. ### Example — FLAC from PROGMEM ```c #include "AudioFileSourcePROGMEM.h" #include "AudioGeneratorFLAC.h" #include "AudioOutputI2S.h" #include "song_flac.h" // const unsigned char song[] PROGMEM = {...}; AudioFileSourcePROGMEM *file = new AudioFileSourcePROGMEM(song, sizeof(song)); AudioGeneratorFLAC *flac = new AudioGeneratorFLAC(); AudioOutputI2S *out = new AudioOutputI2S(); flac->begin(file, out); void loop() { if (flac->isRunning() && !flac->loop()) { flac->stop(); } } ``` ### Example — surfacing FLAC decode warnings ```c void st(void *d, int code, const char *s) { char buf[64]; strncpy(buf, s, sizeof(buf)); // FLAC strings live in static storage Serial.printf("FLAC status %d: %s\n", code, buf); } AudioGeneratorFLAC *flac = new AudioGeneratorFLAC(); flac->RegisterStatusCB(st, NULL); if (!flac->begin(file, out)) { Serial.println("FLAC begin failed (decoder init)"); } ``` ### Cross-references - Base contract: [AudioGenerator](AudioGenerator.md) - Status codes: [errors](../errors.md#audiogeneratorflac) ``` -------------------------------- ### AudioGeneratorTalkie begin() method declaration Source: https://github.com/earlephilhower/esp8266audio/blob/master/_autodocs/api-reference/AudioGeneratorTalkie.md Declaration of the begin() method that initializes the generator with an optional file source and an audio output. ```cpp virtual bool begin(AudioFileSource *source, AudioOutput *output) override; ``` -------------------------------- ### AudioOutputBuffer::begin() Source: https://github.com/earlephilhower/esp8266audio/blob/master/_autodocs/api-reference/AudioOutputMixer.md Delegates the begin operation to the downstream sink. Must be called before consuming samples. ```APIDOC ## AudioOutputBuffer::begin() ### Description Delegates the begin operation to the downstream sink. Must be called before consuming samples. ### Method begin ### Parameters None ### Returns bool - true on success, false on failure ``` -------------------------------- ### AudioFileSourceID3 Source: https://github.com/earlephilhower/esp8266audio/blob/master/_autodocs/api-reference/AudioFileSourceMisc.md Wraps any other AudioFileSource, skips ID3v2 metadata at the start of the stream, and reports tag fields through the metadata callback. ```APIDOC ## AudioFileSourceID3 ### Description Wraps any other `AudioFileSource`, skips ID3v2 metadata at the start of the stream, and reports tag fields through the metadata callback. ### Constructor #### `AudioFileSourceID3(AudioFileSource *src)` | Parameter | Type | Required | Default | Description | |-----------|------|----------|---------|-------------| | src | `AudioFileSource *` | yes | — | Wrapped source (e.g. HTTP stream or SPIFFS file) | ### Methods #### `virtual uint32_t read(void *data, uint32_t len) override` Reads data from the wrapped source, skipping ID3v2 metadata on the first call. #### `virtual bool seek(int32_t pos, int dir) override` Delegates to the wrapped source. #### `virtual bool close() override` Delegates to the wrapped source. #### `virtual bool isOpen() override` Delegates to the wrapped source. #### `virtual uint32_t getSize() override` Delegates to the wrapped source. #### `virtual uint32_t getPos() override` Delegates to the wrapped source. ### Behavior On the first `read()` call the class peeks the `"ID3"` magic, parses the ID3v2 header (v2.2–v2.4), skips the tag block, and emits metadata callbacks. `checked` guards single-pass parsing. - When no ID3 tag is present it raises `cb.md("eof", false, "id3")` and simply forwards reads. - Padding/null frames are skipped; compressed frames are skipped without decompression. ### Metadata frame mapping | Source frame | `cb.md()` type string | |-------------|------------------------| | `TALB` (v2.2: `TAL`) | `"Album"` | | `TIT2` (v2.2: `TT2`) | `"Title"` | | `TPE1` (v2.2: `TP1`) | `"Performer"` | | `TYER` (v2.2: `TYE`) | `"Year"` | | `TRCK` (v2.2: `TRK`) | `"track"` | | `TPOS` (v2.2: `TPA`) | `"Set"` | | `POPM` (v2.2: `POP`) | `"Popularimeter"` | | `TCMP` | `"Compilation"` | | (end of tags) | `"eof"` (payload `"id3"`) | `isUnicode` is true when the frame's text-encoding byte is `1`. Values are truncated to 64 bytes. ### Example — extracting tags ```c #include "AudioFileSourceHTTPStream.h" #include "AudioFileSourceID3.h" #include "AudioGeneratorMP3.h" #include "AudioOutputI2S.h" void meta(void *d, const char *type, bool unicode, const char *str) { Serial.printf("%s = %s\n", type, str); } AudioFileSourceHTTPStream *raw = new AudioFileSourceHTTPStream("http://srv/song.mp3"); AudioFileSourceID3 *file = new AudioFileSourceID3(raw); file->RegisterMetadataCB(meta, NULL); AudioGeneratorMP3 *mp3 = new AudioGeneratorMP3(); AudioOutputI2S *out = new AudioOutputI2S(); mp3->begin(file, out); // Callbacks: "Title", "Performer", "Album", ... then "eof" before the audio starts. ``` ```