It is pretty simple to build a simple mp3 audio player using the Stream API of my Arduino Audio Tools library:
- A SD file is a subclass of an Arduino Stream, so all you need to do is to copy from the file to the desired output stream.
- when we use the EncodedAudioStream as output, we can support different audio formats
- we can add a status flag to halt and continue the processing
- Finally we need to add some logic which handles the end of file to automatically process the next file
- On top of that it is rather easy to add volume control and meta data support.
In order to simplify the usage of my library even more, I decided to provide this functionality as well in a separate class and to prove the point: The AudioPlayer class took only 120 lines of code to implement!
The AudioPlayer supports
- multiple processor architectures
- multiple audio data sources (SD, URL, callbacks)
- different Output Scenarios (I2S, PWM, A2DP etc). Just pass the desired output stream object to the constructor.
- different Decoders for MP3, AAC, WAV. Just pass the desired decoder object to the constructor.
- Volume Control (by calling player.setVolume())
- Stopping and Resuming the processing (by calling player.stop() and player.play())
- You can move to the next file by calling player.next();
- support for Metadata
Dependencies
The sketch is using the following dependencies:
- https://github.com/pschatzmann/arduino-audio-tools
- https://github.com/pschatzmann/arduino-libhelix
- https://github.com/greiman/SdFat
Setup
Install the necessary libraries. Before you start double check your settings in the AudioConfig.h of the arduino-audio-tools project. If the following line is commented out for your processor, remove the comments.
#define USE_SDFAT
A Basic Sketch
The following Arduino Sketch demonstrates how to implement an MP3 Player: which gets the data from a SD drive and provides the audio as analog output: The AudioSourceSdFat class builds on the SdFat Library from Bill Greiman which provides FAT16/FAT32 and exFAT support with long filenames.
#define USE_HELIX
#define USE_SDFAT
#include "AudioTools.h"
#include "AudioCodecs/CodecMP3Helix.h"
using namespace audio_tools;
const char *startFilePath="/";
const char* ext="mp3";
AudioSourceSdFat source(startFilePath, ext);
AnalogAudioStream out;
MP3DecoderHelix decoder;
AudioPlayer player(source, out, decoder);
// Arduino setup
void setup() {
Serial.begin(115200);
AudioLogger::instance().begin(Serial, AudioLogger::Info);
// setup output
auto cfg = out.defaultConfig();
out.begin(cfg);
// setup player
player.begin();
}
// Arduino loop
void loop() {
player.copy();
}
As you can see, this approach has quite some flexibility: if you want to use I2S as output just replace the AnalogAudioStream with I2SStream. If you want to process another file format, just replace the Decoder implementation and if you want to get the audio data from a different source, just replace use a different AudioSource..
Extending the Functionality
With just a few more lines we can add the support for metadata and the filtering of files by name:
#define USE_HELIX
#define USE_SDFAT
#include "AudioTools.h"
#include "AudioCodecs/CodecMP3Helix.h"
using namespace audio_tools;
const char *startFilePath="/";
const char* ext="mp3";
AudioSourceSdFat source(startFilePath, ext);
AnalogAudioStream out;
MP3DecoderHelix decoder;
AudioPlayer player(source, out, decoder);
// metadata callback
void printMetaData(MetaDataType type, const char* str, int len){
Serial.print("==> ");
Serial.print(MetaDataTypeStr[type]);
Serial.print(": ");
Serial.println(str);
}
// Arduino setup
void setup() {
Serial.begin(115200);
AudioLogger::instance().begin(Serial, AudioLogger::Info);
// setup output
auto cfg = out.defaultConfig();
out.begin(cfg);
// setup player
source.setFileFilter("*Bob Dylan*");
player.setCallbackMetadata(printMetaData);
player.begin();
}
// Arduino loop
void loop() {
player.copy();
}
SD Card
Here is the information how to wire the SD card to the ESP32
SD | ESP32 |
---|---|
CS | VSPI-CS0 (GPIO 05) |
SCK | VSPI-CLK (GPIO 18) |
MOSI | VSPI-MOSI (GPIO 23) |
MISO | VSPI-MISO (GPIO 19) |
VCC | VIN (5V) |
GND | GND |
The Output
On the ESP32 the analog output is available on GPIO25 (Channel 1) and GPIO26 (Channel 2).
You can use a piezo electric element or connect some earphones:
Using PlatformIO
You can also implement this sketch in PlatformIO. This has the advantage, that the dependencies get installed automatically. Just use the following platform.ini file:
[platformio]
description = Audio MP3 Player
default_envs = esp32dev
[env:esp32dev]
platform = espressif32
board = esp32dev
framework = arduino
lib_deps = https://github.com/pschatzmann/arduino-audio-tools, https://github.com/pschatzmann/arduino-libhelix, https://github.com/greiman/SdFat
build_flags = -DCORE_DEBUG_LEVEL=5 -Wno-unused-variable -Wno-unused-but-set-variable -Wno-unused-function -Wno-format-extra-args
monitor_speed = 115200
Source code
You can find the source code for this and other audio player examples on Github.
3 Comments
priyanshu jain · 9. March 2023 at 4:42
I have used the same code as above and getting the following error: please guide:
what i need is to play a specific music on button press.
sketch_mar09a:11:1: error: ‘AudioSourceSdFat’ does not name a type
AudioSourceSdFat source(startFilePath, ext);
pschatzmann · 9. March 2023 at 7:40
Please use the examples from Github.
In the meantime, I am supporting not only SDFAT but many other sd libraries as well…
Stephan · 20. April 2023 at 0:23
Thank you for your quick response.