Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 42 additions & 4 deletions src/BackgroundAudioAAC.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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();
}
}
Expand Down Expand Up @@ -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
*/
Expand All @@ -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();
Expand Down Expand Up @@ -269,9 +281,20 @@ class BackgroundAudioAACClass {
}

private:
#ifdef ARDUINO_ARCH_RP2040
static void _irqStub() {
BackgroundAudioAACClass<DataBuffer>::_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<DataBuffer>::_workIRQ);
}
#else
static void _cb(void *ptr) {
((BackgroundAudioAACClass*)ptr)->pump();
}
#endif

void generateOneFrame() {
// Every frame requires shifting all remaining data (6K?) before processing.
Expand Down Expand Up @@ -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) {
Expand All @@ -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<DataBuffer> *_workObj;
#endif

private:
AudioOutputBase *_out = nullptr;
HAACDecoder _hAACDecoder;
Expand All @@ -358,6 +392,10 @@ class BackgroundAudioAACClass {
uint32_t _dumps = 0;
};

#ifdef ARDUINO_ARCH_RP2040
template<class DataBuffer> uint8_t BackgroundAudioAACClass<DataBuffer>::_workIRQ;
template<class DataBuffer> BackgroundAudioAACClass<DataBuffer> *BackgroundAudioAACClass<DataBuffer>::_workObj;
#endif

/**
@brief General purpose AAC background player with an 8KB buffer. Needs to have `write` called repeatedly with data.
Expand Down
45 changes: 45 additions & 0 deletions src/BackgroundAudioMP3.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -268,9 +286,20 @@ class BackgroundAudioMP3Class {
}

private:
#ifdef ARDUINO_ARCH_RP2040
static void _irqStub() {
BackgroundAudioMP3Class<DataBuffer>::_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<DataBuffer>::_workIRQ);
}
#else
static void _cb(void *ptr) {
((BackgroundAudioMP3Class*)ptr)->pump();
}
#endif

void generateOneFrame() {
// Every frame requires shifting all remaining data (6K?) before processing.
Expand Down Expand Up @@ -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) {
Expand All @@ -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<DataBuffer> *_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;
Expand All @@ -376,6 +417,10 @@ class BackgroundAudioMP3Class {
uint32_t _dumps = 0;
};

#ifdef ARDUINO_ARCH_RP2040
template<class DataBuffer> uint8_t BackgroundAudioMP3Class<DataBuffer>::_workIRQ;
template<class DataBuffer> BackgroundAudioMP3Class<DataBuffer> *BackgroundAudioMP3Class<DataBuffer>::_workObj;
#endif

/**
@brief General purpose MP3 background player with an 8KB buffer. Needs to have `write` called repeatedly with data.
Expand Down