1
0
Fork 0

Speaker: Introduce audio playback

Introduce the Speaker class to play audio from the SD card when detecting
tags.
The only audio supported is WAV.

Audio playback is handled via interrupts, so it might try to read from the
SD card at the same time as the LCD class is trying to read new frames.
Update the LCD animation code to temporarily disable audio interrupts while
reading from the SD card.
This commit is contained in:
Teo-CD 2023-10-22 21:19:29 +01:00
parent caff96922e
commit a7c2856ef6
6 changed files with 124 additions and 6 deletions

View file

@ -47,14 +47,23 @@ bool LCD::checkAndDisplay() {
if (!animDir || millis() - lastFrameTime < frameTarget)
return false;
/*
* Audio playback is controlled by interrupts, so it can happen anytime.
* Prevent a potential conflict when reading a frame of animation from the
* SD card and being interrupted by the audio library, which will try to
* read audio data from the SD card at the same time.
*/
AudioNoInterrupts();
File frame = animDir.openNextFile();
if (!frame) {
/* There are no frames anymore, the animation is complete. */
animDir.close();
AudioInterrupts();
return false;
}
frame.read(bitmap, 528);
frame.close();
AudioInterrupts();
lcd.clearDisplay();
lcd.drawBitmap(0, 0, bitmap, 84, 48, 1);

49
src/Speaker.cpp Normal file
View file

@ -0,0 +1,49 @@
//
// Created by Teo-CD on 22/10/23.
//
#include "Speaker.h"
DMAMEM audio_block_t Speaker::audioMemory[audioMemReservation];
bool Speaker::memoryInitialized = false;
void Speaker::init() {
if (memoryInitialized)
return;
AudioStream::initialize_memory(audioMemory, audioMemReservation);
memoryInitialized = true;
}
void Speaker::playNewSound(int8_t ID) {
char filePath[20];
uint8_t rawID = getRawId(ID);
if (!SD.mediaPresent()) {
Com::sendComment("SD Card not present, cannot play sound");
return;
}
if (!isValidId(ID)) {
Com::sendComment("Unknown ID for sound : %d", rawID);
return;
}
if (sdWavSource.isPlaying())
sdWavSource.stop();
snprintf(filePath, 20, "%s/ENTRY.WAV",
(isIdCharacter(ID) ? charDirs : promoDirs)[rawID]);
if (!sd.exists(filePath)) {
Com::sendComment("File %s not present, cannot play sound.", filePath);
return;
}
digitalWrite(pin_Audio_Amp_enable, HIGH);
sdWavSource.play(filePath);
}
bool Speaker::checkPlayingAndDisable() {
bool isPlaying = sdWavSource.isPlaying();
if (!isPlaying)
digitalWrite(pin_Audio_Amp_enable, LOW);
return isPlaying;
}

View file

@ -5,6 +5,7 @@
#include "Com.h"
#include "LCD.h"
#include "RFID.h"
#include "Speaker.h"
__attribute__((noreturn)) int main() {
pinMode(pin_DBG_LED_1, OUTPUT);
@ -40,7 +41,6 @@ __attribute__((noreturn)) int main() {
Serial.begin(115200);
Com::sendComment("System is powered up, running set-up.");
/* TODO: Setups once module structure is up. */
RFID rfid;
digitalWrite(pin_NFC1_RST, HIGH);
rfid.init();
@ -52,17 +52,28 @@ __attribute__((noreturn)) int main() {
digitalWrite(pin_LCD_RST, HIGH);
lcd.init();
/* Don't enable the amp here, only do it when playing to save some power. */
Speaker::init();
Speaker speaker;
Com::sendComment("All modules initialized, entering main loop.");
/* Main loop */
while (true) {
int8_t tagEvent;
/* Display first, in case the RFID communication delays it too much. */
lcd.checkAndDisplay();
speaker.checkPlayingAndDisable();
tagEvent = rfid.checkTags();
if (tagEvent) {
tagEvent = 4;
Com::sendFigUpdate(tagEvent);
/* Start the audio first because of the possible WAV parsing delay. */
speaker.playNewSound(tagEvent);
lcd.startNewAnim(tagEvent);
}
/* TODO: Drop delay, WFE+timer interrupt(s) ? */