diff --git a/src/BackgroundAudioAAC.h b/src/BackgroundAudioAAC.h index e0e3504..1d502ad 100644 --- a/src/BackgroundAudioAAC.h +++ b/src/BackgroundAudioAAC.h @@ -91,6 +91,14 @@ class BackgroundAudioAACClass { return false; } +#ifdef ARDUINO_ARCH_RP2040 + _workIRQ = user_irq_claim_unused(true); + _workObj = this; + irq_set_exclusive_handler(_workIRQ, _irqStub); + irq_set_priority(_workIRQ, 0xc0); // Lowest prio + irq_set_enabled(_workIRQ, true); +#endif + _hAACDecoder = AACInitDecoderPre(_private, sizeof(_private)); if (!_hAACDecoder) { return false; @@ -119,6 +127,10 @@ class BackgroundAudioAACClass { */ void end() { if (_playing) { +#ifdef ARDUINO_ARCH_RP2040 + irq_set_enabled(_workIRQ, false); + user_irq_unclaim(_workIRQ); +#endif _out->end(); } } @@ -205,7 +217,7 @@ class BackgroundAudioAACClass { } /** - @brief Get the number of times the MP3 decoder has underflowed waiting on raw data since `begin` + @brief Get the number of times the AAC decoder has underflowed waiting on raw data since `begin` @return Number of frames of underflow data have occurred */ @@ -232,11 +244,11 @@ class BackgroundAudioAACClass { } /** - @brief Flushes any existing raw data, resets the processor to start a new MP3 + @brief Flushes any existing raw data, resets the processor to start a new AAC @details - This is only needed to abort a currently playing MP3 file (i.e. skipping a track in the middle). - Multiple MP3 files can just be concatenated together in the input buffer with `write` + This is only needed to abort a currently playing AAC file (i.e. skipping a track in the middle). + Multiple AAC files can just be concatenated together in the input buffer with `write` */ void flush() { noInterrupts(); @@ -269,9 +281,20 @@ class BackgroundAudioAACClass { } private: +#ifdef ARDUINO_ARCH_RP2040 + static void _irqStub() { + BackgroundAudioAACClass::_workObj->pump(); + } + + static void _cb(void *ptr) { + // Don't actually do work in the DMA interrupt, do it in the work IRQ context (low prio) + irq_set_pending(BackgroundAudioAACClass::_workIRQ); + } +#else static void _cb(void *ptr) { ((BackgroundAudioAACClass*)ptr)->pump(); } +#endif void generateOneFrame() { // Every frame requires shifting all remaining data (6K?) before processing. @@ -322,6 +345,9 @@ class BackgroundAudioAACClass { ApplyGain((int16_t *)_outSample, _outSamples * 2, _gain); } +#ifdef ARDUINO_ARCH_RP2040 +public: +#endif void pump() { while (_out->availableForWrite() >= (int)(framelen * 2 * sizeof(int16_t))) { if (_paused) { @@ -334,8 +360,16 @@ class BackgroundAudioAACClass { } assert(_out->write((uint8_t *)_outSample, _outSamples * 2 * sizeof(int16_t)) == _outSamples * 2 * sizeof(int16_t)); } +#ifdef ARDUINO_ARCH_RP2040 + irq_clear(_workIRQ); +#endif } +#ifdef ARDUINO_ARCH_RP2040 + static uint8_t _workIRQ; + static BackgroundAudioAACClass *_workObj; +#endif + private: AudioOutputBase *_out = nullptr; HAACDecoder _hAACDecoder; @@ -358,6 +392,10 @@ class BackgroundAudioAACClass { uint32_t _dumps = 0; }; +#ifdef ARDUINO_ARCH_RP2040 +template uint8_t BackgroundAudioAACClass::_workIRQ; +template BackgroundAudioAACClass *BackgroundAudioAACClass::_workObj; +#endif /** @brief General purpose AAC background player with an 8KB buffer. Needs to have `write` called repeatedly with data. diff --git a/src/BackgroundAudioMP3.h b/src/BackgroundAudioMP3.h index 1031d64..58c2407 100644 --- a/src/BackgroundAudioMP3.h +++ b/src/BackgroundAudioMP3.h @@ -79,12 +79,26 @@ class BackgroundAudioMP3Class { } + + /** @brief Starts the background MP3 decoder/player. Will initialize the output device and start sending silence immediately. @return True on success, false if already started. */ bool begin() { + if (_playing || !_out) { + return false; + } + +#ifdef ARDUINO_ARCH_RP2040 + _workIRQ = user_irq_claim_unused(true); + _workObj = this; + irq_set_exclusive_handler(_workIRQ, _irqStub); + irq_set_priority(_workIRQ, 0xc0); // Lowest prio + irq_set_enabled(_workIRQ, true); +#endif + // MP3 processing init mad_stream_init(&_stream); mad_frame_init(&_frame); @@ -115,6 +129,10 @@ class BackgroundAudioMP3Class { */ void end() { if (_playing) { +#ifdef ARDUINO_ARCH_RP2040 + irq_set_enabled(_workIRQ, false); + user_irq_unclaim(_workIRQ); +#endif _out->end(); } _playing = false; @@ -268,9 +286,20 @@ class BackgroundAudioMP3Class { } private: +#ifdef ARDUINO_ARCH_RP2040 + static void _irqStub() { + BackgroundAudioMP3Class::_workObj->pump(); + } + + static void _cb(void *ptr) { + // Don't actually do work in the DMA interrupt, do it in the work IRQ context (low prio) + irq_set_pending(BackgroundAudioMP3Class::_workIRQ); + } +#else static void _cb(void *ptr) { ((BackgroundAudioMP3Class*)ptr)->pump(); } +#endif void generateOneFrame() { // Every frame requires shifting all remaining data (6K?) before processing. @@ -341,6 +370,9 @@ class BackgroundAudioMP3Class { ApplyGain((int16_t*)_synth.pcm.samplesX, framelen * 2, _gain); } +#ifdef ARDUINO_ARCH_RP2040 +public: +#endif void pump() { while (_out->availableForWrite() >= (int)(framelen * 4)) { if (_paused) { @@ -353,12 +385,21 @@ class BackgroundAudioMP3Class { } assert(_out->write((uint8_t *)_synth.pcm.samplesX, _synth.pcm.length * 4) == _synth.pcm.length * 4); } +#ifdef ARDUINO_ARCH_RP2040 + irq_clear(_workIRQ); +#endif } +#ifdef ARDUINO_ARCH_RP2040 + static uint8_t _workIRQ; + static BackgroundAudioMP3Class *_workObj; +#endif + private: AudioOutputBase *_out; bool _playing = false; bool _paused = false; + static const size_t framelen = 1152; static const size_t maxFrameSize = 2881; DataBuffer _ib; @@ -376,6 +417,10 @@ class BackgroundAudioMP3Class { uint32_t _dumps = 0; }; +#ifdef ARDUINO_ARCH_RP2040 +template uint8_t BackgroundAudioMP3Class::_workIRQ; +template BackgroundAudioMP3Class *BackgroundAudioMP3Class::_workObj; +#endif /** @brief General purpose MP3 background player with an 8KB buffer. Needs to have `write` called repeatedly with data.