AutoAnalogAudio: Decoding and playing MP3 files direct from SD card on nRF52
Having fun with nRF52840 devices
I've been playing around quite a bit with my AnalogAudioAudio library since I got it working with I2S, including creating a simple Bluetooth controlled audio player.
Today, I found a simple MP3 decoding library, and decided to test it out. It actually worked! Now I have mp3 files being decoded directly from SD card on nRF52 devices like the Adafruit Feather 52840 or XIAO BLE Sense 52840.
There is lag of a few seconds prior to playback starting, but once that takes place, it seems to play the files well. The code I am using is still in prototyping stages but it does function!
I had to edit an existing MP3 decoding library a bit, but the current code I am using is at https://github.com/TMRh20/microDecoder
Any users that want to test it out can install directly from ZIP from this repository.
I would recommend testing the AutoAnalogAudio library with WAV files before venturing into MP3 playback, but to each his own...
Some example code using the above library is shown below. It has some bugs & quirks, but it does function.
#include <SD.h>
#include <AutoAnalogAudio.h>
#include "mp3.h" // decoder
#include "pcm.h"
mp3 MP3;
pcm audio;
AutoAnalog aaAudio;
const char* audioFilename = "noceil.mp3";
uint8_t SD_CS_PIN = 5; // Set this to your CS pin for the SD card/module
#define USE_I2S 1
char songName[64];
float volumeControl = 0.2;
#define AUDIO_BUFFER_SIZE 6400
void setup() {
pinMode(9, OUTPUT);
digitalWrite(9, HIGH);
pinMode(6, OUTPUT); //Connected to SD pin of MAX98357A
digitalWrite(6, HIGH);
Serial.begin(115200);
while (!Serial) delay(10);
Serial.print("Init SD card...");
if (!SD.begin(SD_CS_PIN)) {
Serial.println("init failed!");
return;
}
Serial.println("SD init ok");
//aaAudio.I2S_PIN_LRCK = 28; // Use different LRCK pin for Feather Express 52840
aaAudio.maxBufferSize = AUDIO_BUFFER_SIZE;
aaAudio.begin(0, 1, USE_I2S);
playAudio(audioFilename);
}
void loop() {
loadBuffer();
// Control via Serial for testing
if (Serial.available()) {
char c = Serial.read();
if (c == '=') {
volumeControl += 0.1;
} else if (c == '-') {
volumeControl -= 0.1;
volumeControl = max(0.0, volumeControl);
} else if (c == 'p') {
playAudio("waitress.mp3");
}
Serial.println(volumeControl);
}
}
File myFile;
void playAudio(const char* audioFile) {
if (myFile) {
myFile.close();
MP3.end();
}
//Open the designated file
myFile = SD.open(audioFile);
MP3.begin(myFile);
MP3.getMetadata();
aaAudio.setSampleRate(MP3.Fs, 1);
Serial.println(MP3.Fs);
aaAudio.dacBitsPerSample = MP3.bitsPerSample;
Serial.println(MP3.bitsPerSample);
}
void loadBuffer() {
if (myFile.available() > AUDIO_BUFFER_SIZE) {
uint32_t sampleCounter = 0;
for (uint32_t i = 0; i < 100; i++) {
audio = MP3.decode();
memcpy(&aaAudio.dacBuffer16[sampleCounter], audio.interleaved, 128); // 128 bytes
sampleCounter += 64; // 64 samples per go
}
for (uint32_t i = 0; i < 6400; i++) {
int16_t sample = aaAudio.dacBuffer16[i];
sample *= volumeControl;
aaAudio.dacBuffer16[i] = sample;
}
aaAudio.feedDAC(0, 6400);
} else {
myFile.seek(0);
}
}
No comments:
Post a Comment