fix(firmware): audio logic does not use all of the available buffers (#7689)

Co-authored-by: Peter Feerick <5500713+pfeerick@users.noreply.github.com>
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
philmoz
2026-09-16 15:12:41 +10:00
committed by GitHub
co-authored by Peter Feerick Claude Sonnet 5
parent d1b2826a91
commit e2968ac864
2 changed files with 54 additions and 22 deletions
+43 -17
View File
@@ -98,6 +98,11 @@ constexpr uint8_t AUDIO_FILENAME_MAXLEN = (AUDIO_LUA_FILENAME_MAXLEN > AUDIO_MOD
#define AUDIO_BUFFER_COUNT (3)
#endif
static_assert((AUDIO_QUEUE_LENGTH & (AUDIO_QUEUE_LENGTH - 1)) == 0,
"AUDIO_QUEUE_LENGTH must be a power of 2");
static_assert(2 * AUDIO_BUFFER_COUNT <= 255,
"AUDIO_BUFFER_COUNT free-running counter must fit in uint8_t");
#define BEEP_MIN_FREQ (150)
#define BEEP_MAX_FREQ (15000)
#define BEEP_DEFAULT_FREQ (2250)
@@ -302,17 +307,28 @@ class AudioBufferFifo {
#endif
private:
// free-running counters in [0, 2*AUDIO_BUFFER_COUNT); each written by only one side
volatile uint8_t readIdx;
volatile uint8_t writeIdx;
inline uint8_t nextBufferIdx(uint8_t idx) const
inline uint8_t nextIndex(uint8_t idx) const
{
return (idx >= AUDIO_BUFFER_COUNT - 1 ? 0 : idx + 1);
return (idx >= 2 * AUDIO_BUFFER_COUNT - 1 ? 0 : idx + 1);
}
bool full() const { return readIdx == nextBufferIdx(writeIdx); }
inline uint8_t slot(uint8_t idx) const
{
return idx >= AUDIO_BUFFER_COUNT ? idx - AUDIO_BUFFER_COUNT : idx;
}
uint8_t used() const
{
uint8_t w = writeIdx, r = readIdx;
return w >= r ? w - r : w + 2 * AUDIO_BUFFER_COUNT - r;
}
bool full() const { return used() == AUDIO_BUFFER_COUNT; }
bool empty() const { return readIdx == writeIdx; }
uint8_t used() const { return (writeIdx - readIdx) % AUDIO_BUFFER_COUNT; }
public:
AudioBufferFifo() : readIdx(0), writeIdx(0)
@@ -324,22 +340,20 @@ class AudioBufferFifo {
// with audioPushBuffer()
AudioBuffer *getEmptyBuffer() const
{
return full() ? nullptr : &audioBuffers[writeIdx];
return full() ? nullptr : &audioBuffers[slot(writeIdx)];
}
// puts filled buffer into FIFO
void audioPushBuffer() { writeIdx = nextBufferIdx(writeIdx); }
void audioPushBuffer() { writeIdx = nextIndex(writeIdx); }
// frees the last played buffer
void freeNextFilledBuffer() { readIdx = nextBufferIdx(readIdx); }
void freeNextFilledBuffer() { readIdx = nextIndex(readIdx); }
// returns a pointer to the audio buffer to be played
const AudioBuffer *getNextFilledBuffer()
{
return empty() ? nullptr : &audioBuffers[readIdx];
return empty() ? nullptr : &audioBuffers[slot(readIdx)];
}
bool filledAtleast(int noBuffers) const { return used() >= noBuffers; }
};
class AudioFragmentFifo
@@ -348,13 +362,25 @@ class AudioFragmentFifo
friend void printAudioVars();
#endif
private:
// free-running counters in [0, 2*AUDIO_QUEUE_LENGTH); each written by only one side
volatile uint8_t ridx;
volatile uint8_t widx;
AudioFragment fragments[AUDIO_QUEUE_LENGTH];
uint8_t nextIdx(uint8_t idx) const
{
return (idx + 1) & (AUDIO_QUEUE_LENGTH - 1);
return (idx + 1) & (2 * AUDIO_QUEUE_LENGTH - 1);
}
uint8_t slot(uint8_t idx) const
{
return idx & (AUDIO_QUEUE_LENGTH - 1);
}
uint8_t used() const
{
uint8_t w = widx, r = ridx;
return w >= r ? w - r : w + 2 * AUDIO_QUEUE_LENGTH - r;
}
public:
@@ -364,7 +390,7 @@ class AudioFragmentFifo
{
uint8_t i = ridx;
while (i != widx) {
AudioFragment & fragment = fragments[i];
AudioFragment & fragment = fragments[slot(i)];
if (fragment.id == id) return true;
i = nextIdx(i);
}
@@ -375,7 +401,7 @@ class AudioFragmentFifo
{
uint8_t i = ridx;
while (i != widx) {
AudioFragment & fragment = fragments[i];
AudioFragment & fragment = fragments[slot(i)];
if (fragment.id == id) fragment.clear();
i = nextIdx(i);
}
@@ -389,7 +415,7 @@ class AudioFragmentFifo
bool full() const
{
return ridx == nextIdx(widx);
return used() == AUDIO_QUEUE_LENGTH;
}
void clear()
@@ -400,8 +426,8 @@ class AudioFragmentFifo
const AudioFragment * get()
{
if (!empty()) {
const AudioFragment * result = &fragments[ridx];
if (!fragments[ridx].repeat--) {
const AudioFragment * result = &fragments[slot(ridx)];
if (!fragments[slot(ridx)].repeat--) {
// repeat is done, move to the next fragment
ridx = nextIdx(ridx);
}
@@ -414,7 +440,7 @@ class AudioFragmentFifo
{
if (!full()) {
// TRACE("fragment %d at %d", fragment.type, widx);
fragments[widx] = fragment;
fragments[slot(widx)] = fragment;
widx = nextIdx(widx);
}
}
+11 -5
View File
@@ -1432,11 +1432,17 @@ void printAudioVars()
}
}
cliSerialPrint("FragmentFifo: ridx: %d, widx: %d",
audioQueue.fragmentsFifo.ridx, audioQueue.fragmentsFifo.widx);
cliSerialPrint("audioQueue: readIdx: %d, writeIdx: %d, full: %d",
audioQueue.buffersFifo.readIdx, audioQueue.buffersFifo.writeIdx,
audioQueue.buffersFifo.bufferFull);
cliSerialPrint("FragmentFifo: ridx: %d (slot %d), widx: %d (slot %d)",
audioQueue.fragmentsFifo.ridx,
audioQueue.fragmentsFifo.slot(audioQueue.fragmentsFifo.ridx),
audioQueue.fragmentsFifo.widx,
audioQueue.fragmentsFifo.slot(audioQueue.fragmentsFifo.widx));
cliSerialPrint("audioQueue: readIdx: %d (slot %d), writeIdx: %d (slot %d), full: %d",
audioQueue.buffersFifo.readIdx,
audioQueue.buffersFifo.slot(audioQueue.buffersFifo.readIdx),
audioQueue.buffersFifo.writeIdx,
audioQueue.buffersFifo.slot(audioQueue.buffersFifo.writeIdx),
audioQueue.buffersFifo.full());
cliSerialPrint("normalContext: %u",
(uint32_t)audioQueue.normalContext.fragment.type);