snapshot
This commit is contained in:
4
libraries/audio-tools/examples/examples-player/README.md
Normal file
4
libraries/audio-tools/examples/examples-player/README.md
Normal file
@@ -0,0 +1,4 @@
|
||||
# AudioPlayer Examples
|
||||
|
||||
see [the Wiki](https://github.com/pschatzmann/arduino-audio-tools/wiki/The-Audio-Player-Class)
|
||||
You can find some more examples in the AudioKit
|
||||
@@ -0,0 +1,53 @@
|
||||
# A Simple Callback Audio Player
|
||||
|
||||
The example demonstrates how to implement an __MP3 Player__ which __provides the data via callbacks__ and sends the audio via I2S to an external DAC.
|
||||
|
||||
This demonstrates the minimum implementation. I recommend however to provide implementations for the other callback methods to enhance the functionality: e.g absolute positioning, file selection by name etc.
|
||||
|
||||
|
||||
## 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
|
||||
|
||||
|
||||
### External DAC:
|
||||
|
||||
For my tests I am using the 24-bit PCM5102 PCM5102A Stereo DAC Digital-to-analog Converter PLL Voice Module pHAT
|
||||
|
||||

|
||||
|
||||
I am just using the default pins defined by the framework. However I could change them with the help of the config object. The mute pin can be defined in the constructor of the I2SStream - by not defining anything we use the default which is GPIO23
|
||||
|
||||
|
||||
DAC | ESP32
|
||||
-----|----------------
|
||||
VCC | 5V
|
||||
GND | GND
|
||||
BCK | BCK (GPIO14)
|
||||
DIN | OUT (GPIO22)
|
||||
LCK | BCK (GPIO15)
|
||||
FMT | GND
|
||||
XMT | 3V (or another GPIO PIN which is set to high)
|
||||
|
||||
- DMP - De-emphasis control for 44.1kHz sampling rate(1): Off (Low) / On (High)
|
||||
- FLT - Filter select : Normal latency (Low) / Low latency (High)
|
||||
- SCL - System clock input (probably SCL on your board).
|
||||
- FMT - Audio format selection : I2S (Low) / Left justified (High)
|
||||
- XMT - Soft mute control(1): Soft mute (Low) / soft un-mute (High)
|
||||
|
||||
|
||||
|
||||
## Dependencies
|
||||
|
||||
- https://github.com/pschatzmann/arduino-audio-tools
|
||||
- https://github.com/pschatzmann/arduino-libhelix
|
||||
- https://github.com/greiman/SdFat
|
||||
@@ -0,0 +1,71 @@
|
||||
/**
|
||||
* @file player-sd-callback.ino
|
||||
* @brief see https://github.com/pschatzmann/arduino-audio-tools/blob/main/examples/examples-player/player-callback-i2s/README.md
|
||||
*
|
||||
* @author Phil Schatzmann
|
||||
* @copyright GPLv3
|
||||
*/
|
||||
|
||||
|
||||
// Install https://github.com/pschatzmann/arduino-libhelix.git
|
||||
|
||||
#include "Arduino.h"
|
||||
#include "AudioTools.h"
|
||||
#include "AudioTools/AudioCodecs/CodecMP3Helix.h"
|
||||
#include <SPI.h>
|
||||
#include <SD.h>
|
||||
|
||||
|
||||
// forward declarations
|
||||
void callbackInit();
|
||||
Stream* callbackNextStream(int offset);
|
||||
|
||||
// data
|
||||
const int chipSelect=PIN_CS;
|
||||
AudioSourceCallback source(callbackNextStream, callbackInit);
|
||||
I2SStream i2s;
|
||||
MP3DecoderHelix decoder;
|
||||
AudioPlayer player(source, i2s, decoder);
|
||||
File audioFile;
|
||||
File dir;
|
||||
|
||||
void callbackInit() {
|
||||
// make sure that the directory contains only mp3 files
|
||||
dir = SD.open("/TomWaits");
|
||||
}
|
||||
|
||||
Stream* callbackNextStream(int offset) {
|
||||
audioFile.close();
|
||||
// the next files must be a mp3 file
|
||||
for (int j=0;j<offset;j++)
|
||||
audioFile = dir.openNextFile();
|
||||
return &audioFile;
|
||||
}
|
||||
|
||||
void callbackPrintMetaData(MetaDataType type, const char* str, int len){
|
||||
Serial.print("==> ");
|
||||
Serial.print(toStr(type));
|
||||
Serial.print(": ");
|
||||
Serial.println(str);
|
||||
}
|
||||
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
|
||||
|
||||
// setup SD
|
||||
SD.begin(chipSelect);
|
||||
|
||||
// setup output
|
||||
auto cfg = i2s.defaultConfig(TX_MODE);
|
||||
i2s.begin(cfg);
|
||||
|
||||
// setup player
|
||||
player.setMetadataCallback(callbackPrintMetaData);
|
||||
player.begin();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
player.copy();
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
/**
|
||||
* @file player-ftp-audiokit.ino
|
||||
* @brief AudioPlayer example that is using FTP as audio source
|
||||
* @author Phil Schatzmann
|
||||
* @copyright GPLv3
|
||||
*/
|
||||
|
||||
#include "WiFi.h"
|
||||
#include "AudioTools.h"
|
||||
#include "AudioTools/AudioCodecs/CodecMP3Helix.h"
|
||||
#include "AudioTools/AudioLibs/AudioBoardStream.h"
|
||||
#include "AudioTools/Disk/AudioSourceFTP.h"
|
||||
|
||||
const char* path = "Music/Tracy Chapman/Matters of the Heart";
|
||||
const char* ext = "mp3";
|
||||
const char* ftp_user = "user";
|
||||
const char* ftp_pwd = "password";
|
||||
const char* ssid = "ssid";
|
||||
const char* ssid_pwd = "ssid-password";
|
||||
|
||||
FTPClient<WiFiClient> ftp;
|
||||
AudioSourceFTP<WiFiClient> source(ftp, path, ext);
|
||||
AudioBoardStream i2s(AudioKitEs8388V1);
|
||||
MP3DecoderHelix decoder;
|
||||
AudioPlayer player(source, i2s, decoder);
|
||||
|
||||
void next(bool, int, void*) { player.next(); }
|
||||
|
||||
void previous(bool, int, void*) { player.previous(); }
|
||||
|
||||
void startStop(bool, int, void*) { player.setActive(!player.isActive()); }
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
|
||||
FTPLogger::setOutput(Serial);
|
||||
FTPLogger::setLogLevel(LOG_DEBUG);
|
||||
|
||||
// connect to WIFI
|
||||
WiFi.begin(ssid, ssid_pwd);
|
||||
while (WiFi.status() != WL_CONNECTED) {
|
||||
delay(500);
|
||||
Serial.print(".");
|
||||
}
|
||||
Serial.println();
|
||||
WiFi.setSleep(false);
|
||||
|
||||
// connect to ftp
|
||||
if (!ftp.begin(IPAddress(192,168,1,39), ftp_user, ftp_pwd)){
|
||||
Serial.println("ftp failed");
|
||||
stop();
|
||||
}
|
||||
|
||||
// setup output
|
||||
auto cfg = i2s.defaultConfig(TX_MODE);
|
||||
if (!i2s.begin(cfg)){
|
||||
Serial.println("i2s failed");
|
||||
stop();
|
||||
}
|
||||
|
||||
// setup additional buttons
|
||||
i2s.addDefaultActions();
|
||||
i2s.addAction(i2s.getKey(1), startStop);
|
||||
i2s.addAction(i2s.getKey(4), next);
|
||||
i2s.addAction(i2s.getKey(3), previous);
|
||||
|
||||
// setup player
|
||||
player.setVolume(0.7);
|
||||
// load the directory
|
||||
if (!player.begin()){
|
||||
Serial.println("player failed");
|
||||
stop();
|
||||
}
|
||||
}
|
||||
|
||||
void loop() {
|
||||
player.copy();
|
||||
i2s.processActions();
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,43 @@
|
||||
/**
|
||||
* @file player-littlefs-i2s.ino
|
||||
* @brief example using the LittleFS library
|
||||
*
|
||||
* @author Phil Schatzmann
|
||||
* @copyright GPLv3
|
||||
*/
|
||||
|
||||
#include "AudioTools.h"
|
||||
#include "AudioTools/Disk/AudioSourceLittleFS.h"
|
||||
#include "AudioTools/AudioCodecs/CodecMP3Helix.h"
|
||||
|
||||
const char *startFilePath="/";
|
||||
const char* ext="mp3";
|
||||
AudioSourceLittleFS source(startFilePath, ext);
|
||||
I2SStream i2s;
|
||||
MP3DecoderHelix decoder;
|
||||
AudioPlayer player(source, i2s, decoder);
|
||||
|
||||
void printMetaData(MetaDataType type, const char* str, int len){
|
||||
Serial.print("==> ");
|
||||
Serial.print(toStr(type));
|
||||
Serial.print(": ");
|
||||
Serial.println(str);
|
||||
}
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
|
||||
|
||||
// setup output
|
||||
auto cfg = i2s.defaultConfig(TX_MODE);
|
||||
i2s.begin(cfg);
|
||||
|
||||
// setup player
|
||||
//source.setFileFilter("*Bob Dylan*");
|
||||
player.setMetadataCallback(printMetaData);
|
||||
player.begin();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
player.copy();
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
## Using the AI Thinker ESP32 Audio Kit as SD Player
|
||||
|
||||
I found some cheap [AI Thinker ESP32 Audio Kit V2.2](https://docs.ai-thinker.com/en/esp32-audio-kit) on AliExpress and because I was tired of all the wires I had to connect to implement my different scenarios that are possible with my [Arduino Audio Tools Library](https://github.com/pschatzmann/arduino-audio-tools), I thought it to be a good idea to buy this board.
|
||||
|
||||
<img src="https://pschatzmann.github.io/Resources/img/audio-toolkit.png" alt="Audio Kit" />
|
||||
|
||||
You dont need to bother about any wires because everything is on one nice board. Just just need to install the dependencies
|
||||
To access the files we use the SD library.
|
||||
|
||||
### Note
|
||||
|
||||
The log level has been set to Info to help you to identify any problems. Please change it to AudioLogger::Warning to get the best sound quality!
|
||||
|
||||
|
||||
## Dependencies
|
||||
|
||||
You need to install the following libraries:
|
||||
|
||||
- https://github.com/pschatzmann/arduino-audio-tools
|
||||
- https://github.com/pschatzmann/arduino-libhelix
|
||||
- https://github.com/pschatzmann/arduino-audio-driver
|
||||
@@ -0,0 +1,66 @@
|
||||
/**
|
||||
* @file player-sd-audiokit.ino
|
||||
* @brief see https://github.com/pschatzmann/arduino-audio-tools/blob/main/examples/examples-audiokit/player-sd-audiokit/README.md
|
||||
* Make sure that the pins are set to off, on, on, off, off
|
||||
* @author Phil Schatzmann
|
||||
* @copyright GPLv3
|
||||
*/
|
||||
|
||||
|
||||
#include "AudioTools.h"
|
||||
#include "AudioTools/AudioLibs/AudioBoardStream.h"
|
||||
#include "AudioTools/Disk/AudioSourceSD.h" // or AudioSourceIdxSD.h
|
||||
#include "AudioTools/AudioCodecs/CodecMP3Helix.h"
|
||||
|
||||
const char *startFilePath="/";
|
||||
const char* ext="mp3";
|
||||
AudioSourceSD source(startFilePath, ext, PIN_AUDIO_KIT_SD_CARD_CS);
|
||||
AudioBoardStream kit(AudioKitEs8388V1);
|
||||
MP3DecoderHelix decoder; // or change to MP3DecoderMAD
|
||||
AudioPlayer player(source, kit, decoder);
|
||||
|
||||
void next(bool, int, void*) {
|
||||
player.next();
|
||||
}
|
||||
|
||||
void previous(bool, int, void*) {
|
||||
player.previous();
|
||||
}
|
||||
|
||||
void startStop(bool, int, void*) {
|
||||
player.setActive(!player.isActive());
|
||||
}
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
|
||||
|
||||
// setup output
|
||||
auto cfg = kit.defaultConfig(TX_MODE);
|
||||
// sd_active is setting up SPI with the right SD pins by calling
|
||||
// SPI.begin(PIN_AUDIO_KIT_SD_CARD_CLK, PIN_AUDIO_KIT_SD_CARD_MISO, PIN_AUDIO_KIT_SD_CARD_MOSI, PIN_AUDIO_KIT_SD_CARD_CS);
|
||||
cfg.sd_active = true;
|
||||
kit.begin(cfg);
|
||||
|
||||
// setup additional buttons
|
||||
kit.addDefaultActions();
|
||||
kit.addAction(kit.getKey(1), startStop);
|
||||
kit.addAction(kit.getKey(4), next);
|
||||
kit.addAction(kit.getKey(3), previous);
|
||||
|
||||
|
||||
// setup player
|
||||
player.setVolume(0.7);
|
||||
player.begin();
|
||||
|
||||
// select file with setPath() or setIndex()
|
||||
//player.setPath("/ZZ Top/Unknown Album/Lowrider.mp3");
|
||||
//player.setIndex(1); // 2nd file
|
||||
|
||||
}
|
||||
|
||||
void loop() {
|
||||
player.copy();
|
||||
kit.processActions();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/**
|
||||
* @file player-sd-i2s.ino
|
||||
* @brief example using the SD library
|
||||
*
|
||||
* @author Phil Schatzmann
|
||||
* @copyright GPLv3
|
||||
*/
|
||||
|
||||
#include "AudioTools.h"
|
||||
#include "AudioTools/Disk/AudioSourceSD.h"
|
||||
#include "AudioTools/AudioCodecs/CodecMP3Helix.h"
|
||||
|
||||
const char *startFilePath="/";
|
||||
const char* ext="mp3";
|
||||
AudioSourceSD source(startFilePath, ext);
|
||||
I2SStream i2s;
|
||||
MP3DecoderHelix decoder;
|
||||
AudioPlayer player(source, i2s, decoder);
|
||||
|
||||
void printMetaData(MetaDataType type, const char* str, int len){
|
||||
Serial.print("==> ");
|
||||
Serial.print(toStr(type));
|
||||
Serial.print(": ");
|
||||
Serial.println(str);
|
||||
}
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
|
||||
|
||||
// setup output
|
||||
auto cfg = i2s.defaultConfig(TX_MODE);
|
||||
i2s.begin(cfg);
|
||||
|
||||
// setup player
|
||||
//source.setFileFilter("*Bob Dylan*");
|
||||
player.setMetadataCallback(printMetaData);
|
||||
player.begin();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
player.copy();
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/**
|
||||
* @file player-sd-i2s.ino
|
||||
* @brief example using the SD library that shows how to support m4a
|
||||
* aac, mp3 and alac files. We provid a MultiDecoder to the ContainerM4A
|
||||
* so that the container can decode aac and alac. We also provide it to
|
||||
* the AudioPlayer so that we can play aac, alac, mp4 and m4a files. If
|
||||
* you only want to play m4a files, you can provide the ContainerM4A directly.
|
||||
*
|
||||
* @author Phil Schatzmann
|
||||
* @copyright GPLv3
|
||||
*/
|
||||
|
||||
#include "AudioTools.h"
|
||||
#include "AudioTools/Disk/AudioSourceSD.h"
|
||||
#include "AudioTools/AudioCodecs/CodecALAC.h"
|
||||
#include "AudioTools/AudioCodecs/CodecAACHelix.h"
|
||||
#include "AudioTools/AudioCodecs/CodecMP3Helix.h"
|
||||
#include "AudioTools/AudioCodecs/ContainerM4A.h"
|
||||
#include "AudioTools/AudioCodecs/MultiDecoder.h"
|
||||
#include "AudioTools/AudioLibs/AudioBoardStream.h" // install https://github.com/pschatzmann/arduino-audio-driver
|
||||
|
||||
|
||||
const char *startFilePath="/m4a";
|
||||
const char* ext="m4a";
|
||||
AudioSourceSD source(startFilePath, ext);
|
||||
AudioBoardStream i2s(AudioKitEs8388V1); // or e.g. I2SStream i2s;
|
||||
MultiDecoder multi_decoder;
|
||||
ContainerM4A dec_m4a(multi_decoder);
|
||||
AACDecoderHelix dec_aac;
|
||||
MP3DecoderHelix dec_mp3;
|
||||
DecoderALAC dec_alac;
|
||||
AudioPlayer player(source, i2s, multi_decoder);
|
||||
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
|
||||
|
||||
// setup multi decoder
|
||||
multi_decoder.addDecoder(dec_m4a, "audio/m4a");
|
||||
multi_decoder.addDecoder(dec_alac,"audio/alac");
|
||||
multi_decoder.addDecoder(dec_aac,"audio/aac");
|
||||
multi_decoder.addDecoder(dec_mp3,"audio/mp3");
|
||||
|
||||
// setup output
|
||||
auto cfg = i2s.defaultConfig(TX_MODE);
|
||||
i2s.begin(cfg);
|
||||
|
||||
// setup player
|
||||
//source.setFileFilter("*Bob Dylan*");
|
||||
player.begin();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
player.copy();
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
# A Simple SdFat Audio Player
|
||||
|
||||
It was pretty simple to build a simple audio player with the help of the Stream API. A SD file is a sublass of an Arduino Stream, so all you need to do is to copy from the file to the desired output strem. Finally you need to add some logic which handles the end of file to automatically process the next file and maybe a status flag to halt and contine the processing. In addition it adds only a little bit of additional complexity to add volume control and meta data support.
|
||||
|
||||
In order to simplify things, I decided to provide this functionality as well 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__
|
||||
|
||||
The example demonstrates how to implement an __MP3 Player__: which provides the data from a SD drive and provides the audio via I2S as __anlog output__: The __AudioSourceSdFat class__ builds on the [SdFat Library](https://github.com/greiman/SdFat) from Bill Greiman which provides FAT16/FAT32 and exFAT support.
|
||||
|
||||
## 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
|
||||
|
||||

|
||||
|
||||
|
||||
### Output Device: Piezo Electric Element
|
||||
|
||||
To test the output I am using piezo electric elements
|
||||
|
||||

|
||||
|
||||
It should also be possible to connect a headphone to the output pins.
|
||||
|
||||
|
||||
| PIEZO Left | ESP32
|
||||
| ------------| --------------
|
||||
| + | GPIO25
|
||||
| - | GND
|
||||
|
||||
| PIEZO2 Rigt | ESP32
|
||||
| ------------| --------------
|
||||
| + | GPIO26
|
||||
| - | GND
|
||||
|
||||
|
||||
## Dependencies
|
||||
|
||||
- https://github.com/pschatzmann/arduino-audio-tools
|
||||
- https://github.com/pschatzmann/arduino-libhelix
|
||||
- https://github.com/greiman/SdFat
|
||||
@@ -0,0 +1,46 @@
|
||||
/**
|
||||
* @file player-sdfat-analog.ino
|
||||
* @brief see https://github.com/pschatzmann/arduino-audio-tools/blob/main/examples/examples-player/player-sdfat-analog/README.md
|
||||
*
|
||||
* @author Phil Schatzmann
|
||||
* @copyright GPLv3
|
||||
*/
|
||||
|
||||
|
||||
#include "AudioTools.h"
|
||||
#include "AudioTools/Disk/AudioSourceSDFAT.h"
|
||||
#include "AudioTools/AudioCodecs/CodecMP3Helix.h"
|
||||
|
||||
|
||||
const char *startFilePath="/";
|
||||
const char* ext="mp3";
|
||||
AudioSourceSDFAT source(startFilePath, ext);
|
||||
AnalogAudioStream out;
|
||||
MP3DecoderHelix decoder;
|
||||
AudioPlayer player(source, out, decoder);
|
||||
|
||||
|
||||
void printMetaData(MetaDataType type, const char* str, int len){
|
||||
Serial.print("==> ");
|
||||
Serial.print(toStr(type));
|
||||
Serial.print(": ");
|
||||
Serial.println(str);
|
||||
}
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
|
||||
|
||||
// setup output
|
||||
auto cfg = out.defaultConfig();
|
||||
out.begin(cfg);
|
||||
|
||||
// setup player
|
||||
//source.setFileFilter("*Bob Dylan*");
|
||||
player.setMetadataCallback(printMetaData);
|
||||
player.begin();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
player.copy();
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
## Using the AI Thinker ESP32 Audio Kit as SD Player
|
||||
|
||||
I found some cheap [AI Thinker ESP32 Audio Kit V2.2](https://docs.ai-thinker.com/en/esp32-audio-kit) on AliExpress and because I was tired of all the wires I had to connect to implement my different scenarios that are possible with my [Arduino Audio Tools Library](https://github.com/pschatzmann/arduino-audio-tools), I thought it to be a good idea to buy this board.
|
||||
|
||||
<img src="https://pschatzmann.github.io/Resources/img/audio-toolkit.png" alt="Audio Kit" />
|
||||
|
||||
You dont need to bother about any wires because everything is on one nice board. Just just need to install the dependencies
|
||||
To access the files we use the greiman/SdFat library.
|
||||
|
||||
### Note
|
||||
|
||||
The log level has been set to Info to help you to identify any problems. Please change it to AudioLogger::Warning to get the best sound quality!
|
||||
|
||||
|
||||
## Dependencies
|
||||
|
||||
You need to install the following libraries:
|
||||
|
||||
- https://github.com/pschatzmann/arduino-audio-tools
|
||||
- https://github.com/pschatzmann/arduino-libhelix
|
||||
- https://github.com/pschatzmann/arduino-audio-driver
|
||||
- https://github.com/greiman/SdFat
|
||||
@@ -0,0 +1,63 @@
|
||||
/**
|
||||
* @file player-sd-audiokit.ino
|
||||
* @brief see https://github.com/pschatzmann/arduino-audio-tools/blob/main/examples/examples-audiokit/player-sdfat-audiokit/README.md
|
||||
* Make sure that the pins are set to off, on, on, off, off
|
||||
* @author Phil Schatzmann
|
||||
* @copyright GPLv3
|
||||
*/
|
||||
|
||||
|
||||
#include "AudioTools.h"
|
||||
#include "AudioTools/AudioLibs/AudioBoardStream.h"
|
||||
#include "AudioTools/Disk/AudioSourceSDFAT.h" // or AudioSourceIdxSDFAT.h
|
||||
#include "AudioTools/AudioCodecs/CodecMP3Helix.h"
|
||||
|
||||
const char *startFilePath="/";
|
||||
const char* ext="mp3";
|
||||
SdSpiConfig sdcfg(PIN_AUDIO_KIT_SD_CARD_CS, DEDICATED_SPI, SD_SCK_MHZ(10) , &SPI);
|
||||
AudioSourceSDFAT source(startFilePath, ext, sdcfg);
|
||||
AudioBoardStream kit(AudioKitEs8388V1);
|
||||
MP3DecoderHelix decoder; // or change to MP3DecoderMAD
|
||||
AudioPlayer player(source, kit, decoder);
|
||||
|
||||
void next(bool, int, void*) {
|
||||
player.next();
|
||||
}
|
||||
|
||||
void previous(bool, int, void*) {
|
||||
player.previous();
|
||||
}
|
||||
|
||||
void startStop(bool, int, void*) {
|
||||
player.setActive(!player.isActive());
|
||||
}
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
|
||||
|
||||
// setup output
|
||||
auto cfg = kit.defaultConfig(TX_MODE);
|
||||
kit.begin(cfg);
|
||||
|
||||
// setup additional buttons
|
||||
kit.addDefaultActions();
|
||||
kit.addAction(kit.getKey(1), startStop);
|
||||
kit.addAction(kit.getKey(4), next);
|
||||
kit.addAction(kit.getKey(3), previous);
|
||||
|
||||
|
||||
// setup player
|
||||
player.setVolume(0.7);
|
||||
player.begin();
|
||||
|
||||
// select file with setPath() or setIndex()
|
||||
//player.setPath("/ZZ Top/Unknown Album/Lowrider.mp3");
|
||||
//player.setIndex(1); // 2nd file
|
||||
|
||||
}
|
||||
|
||||
void loop() {
|
||||
player.copy();
|
||||
kit.processActions();
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/**
|
||||
* @file player-sdfat-ffti2s.ino
|
||||
* @brief Audio Player with output to I2S and FFT
|
||||
*
|
||||
* @author Phil Schatzmann
|
||||
* @copyright GPLv3
|
||||
*/
|
||||
|
||||
|
||||
#include "AudioTools.h"
|
||||
#include "AudioTools/Disk/AudioSourceSD.h"
|
||||
#include "AudioTools/AudioCodecs/CodecMP3Helix.h"
|
||||
#include "AudioTools/AudioLibs/AudioRealFFT.h" // or AudioKissFFT or others
|
||||
|
||||
const char *startFilePath="/";
|
||||
const char* ext="mp3";
|
||||
AudioSourceSD source(startFilePath, ext);
|
||||
MultiOutput multi_output;
|
||||
MP3DecoderHelix decoder;
|
||||
AudioPlayer player(source, multi_output, decoder);
|
||||
I2SStream i2s; // output to i2s
|
||||
AudioRealFFT fft; // or AudioKissFFT or others
|
||||
|
||||
// display fft result
|
||||
void fftResult(AudioFFTBase &fft){
|
||||
float diff;
|
||||
auto result = fft.result();
|
||||
if (result.magnitude>100){
|
||||
Serial.print(result.frequency);
|
||||
Serial.print(" ");
|
||||
Serial.print(result.magnitude);
|
||||
Serial.print(" => ");
|
||||
Serial.print(result.frequencyAsNote(diff));
|
||||
Serial.print( " diff: ");
|
||||
Serial.println(diff);
|
||||
}
|
||||
}
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
|
||||
|
||||
// setup I2S
|
||||
auto cfg = i2s.defaultConfig(TX_MODE);
|
||||
i2s.begin(cfg);
|
||||
|
||||
// Setup FFT
|
||||
auto tcfg = fft.defaultConfig();
|
||||
tcfg.copyFrom(cfg);
|
||||
tcfg.length = 1024;
|
||||
tcfg.callback = &fftResult;
|
||||
fft.begin(tcfg);
|
||||
|
||||
// Setup Multioutput
|
||||
multi_output.add(fft);
|
||||
multi_output.add(i2s);
|
||||
|
||||
// setup player
|
||||
//source.setFileFilter("*Bob Dylan*");
|
||||
player.begin();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
player.copy();
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
# A Simple SdFat Audio Player
|
||||
|
||||
It was pretty simple to build a simple audio player with the help of the Stream API. A SD file is a sublass of an Arduino Stream, so all you need to do is to copy from the file to the desired output strem. Finally you need to add some logic which handles the end of file to automatically process the next file and maybe a status flag to halt and contine the processing. In addition it adds only a little bit of additional complexity to add volume control and meta data support.
|
||||
|
||||
In order to simplify things, I decided to provide this functionality as well 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__
|
||||
|
||||
The example demonstrates how to implement an __MP3 Player__: which provides the data from a SD drive and sends the audio via I2S to an __external DAC__: The __AudioSourceSdFat class__ builds on the [SdFat Library](https://github.com/greiman/SdFat) from Bill Greiman which provides FAT16/FAT32 and exFAT support.
|
||||
|
||||
## 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
|
||||
|
||||

|
||||
|
||||
### External DAC:
|
||||
|
||||
For my tests I am using the 24-bit PCM5102 PCM5102A Stereo DAC Digital-to-analog Converter PLL Voice Module pHAT
|
||||
|
||||

|
||||
|
||||
I am just using the default pins defined by the framework. However I could change them with the help of the config object. The mute pin can be defined in the constructor of the I2SStream - by not defining anything we use the default which is GPIO23
|
||||
|
||||
|
||||
DAC | ESP32
|
||||
-----|----------------
|
||||
VCC | 5V
|
||||
GND | GND
|
||||
BCK | BCK (GPIO14)
|
||||
DIN | OUT (GPIO22)
|
||||
LCK | BCK (GPIO15)
|
||||
FMT | GND
|
||||
XMT | 3V (or another GPIO PIN which is set to high)
|
||||
|
||||
- DMP - De-emphasis control for 44.1kHz sampling rate(1): Off (Low) / On (High)
|
||||
- FLT - Filter select : Normal latency (Low) / Low latency (High)
|
||||
- SCL - System clock input (probably SCL on your board).
|
||||
- FMT - Audio format selection : I2S (Low) / Left justified (High)
|
||||
- XMT - Soft mute control(1): Soft mute (Low) / soft un-mute (High)
|
||||
|
||||
|
||||
|
||||
|
||||
## Dependencies
|
||||
|
||||
- https://github.com/pschatzmann/arduino-audio-tools
|
||||
- https://github.com/pschatzmann/arduino-libhelix
|
||||
- https://github.com/greiman/SdFat
|
||||
@@ -0,0 +1,46 @@
|
||||
/**
|
||||
* @file player-sdfat-i2s.ino
|
||||
* @brief see https://github.com/pschatzmann/arduino-audio-tools/blob/main/examples/examples-player/player-sdfat-i2s/README.md
|
||||
*
|
||||
* @author Phil Schatzmann
|
||||
* @copyright GPLv3
|
||||
*/
|
||||
|
||||
|
||||
#include "AudioTools.h"
|
||||
#include "AudioTools/Disk/AudioSourceSDFAT.h"
|
||||
#include "AudioTools/AudioCodecs/CodecMP3Helix.h"
|
||||
|
||||
|
||||
const char *startFilePath="/";
|
||||
const char* ext="mp3";
|
||||
AudioSourceSDFAT source(startFilePath, ext);
|
||||
I2SStream i2s;
|
||||
MP3DecoderHelix decoder;
|
||||
AudioPlayer player(source, i2s, decoder);
|
||||
|
||||
|
||||
void printMetaData(MetaDataType type, const char* str, int len){
|
||||
Serial.print("==> ");
|
||||
Serial.print(toStr(type));
|
||||
Serial.print(": ");
|
||||
Serial.println(str);
|
||||
}
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
|
||||
|
||||
// setup output
|
||||
auto cfg = i2s.defaultConfig(TX_MODE);
|
||||
i2s.begin(cfg);
|
||||
|
||||
// setup player
|
||||
//source.setFileFilter("*Bob Dylan*");
|
||||
player.setMetadataCallback(printMetaData);
|
||||
player.begin();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
player.copy();
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
## Using the AI Thinker ESP32 Audio Kit as SD Player
|
||||
|
||||
I found some cheap [AI Thinker ESP32 Audio Kit V2.2](https://docs.ai-thinker.com/en/esp32-audio-kit) on AliExpress and because I was tired of all the wires I had to connect to implement my different scenarios that are possible with my [Arduino Audio Tools Library](https://github.com/pschatzmann/arduino-audio-tools), I thought it to be a good idea to buy this board.
|
||||
|
||||
<img src="https://pschatzmann.github.io/Resources/img/audio-toolkit.png" alt="Audio Kit" />
|
||||
|
||||
You dont need to bother about any wires because everything is on one nice board. Just just need to install the dependencies
|
||||
|
||||
In this example we use the SDMMC library which is provided by the ESP32. On the Audiokit all the pins must be on the on position!
|
||||
|
||||
### Note
|
||||
|
||||
The log level has been set to Info to help you to identify any problems. Please change it to AudioLogger::Warning to get the best sound quality!
|
||||
|
||||
|
||||
## Dependencies
|
||||
|
||||
You need to install the following libraries:
|
||||
|
||||
- https://github.com/pschatzmann/arduino-audio-tools
|
||||
- https://github.com/pschatzmann/arduino-libhelix
|
||||
- https://github.com/pschatzmann/arduino-audio-driver
|
||||
@@ -0,0 +1,43 @@
|
||||
/**
|
||||
* @file player-sd-audiokit.ino
|
||||
* @brief see https://github.com/pschatzmann/arduino-audio-tools/blob/main/examples/examples-audiokit/player-sdmmc-audiokit/README.md
|
||||
* Make sure that the pins are set to on, on, on, on, on
|
||||
* @author Phil Schatzmann
|
||||
* @copyright GPLv3
|
||||
*/
|
||||
|
||||
#include "AudioTools.h"
|
||||
#include "AudioTools/AudioLibs/AudioBoardStream.h"
|
||||
#include "AudioTools/Disk/AudioSourceSDMMC.h" // or AudioSourceIdxSDMMC.h
|
||||
#include "AudioTools/AudioCodecs/CodecMP3Helix.h"
|
||||
|
||||
const char *startFilePath="/";
|
||||
const char* ext="mp3";
|
||||
AudioSourceSDMMC source(startFilePath, ext);
|
||||
AudioBoardStream kit(AudioKitEs8388V1);
|
||||
MP3DecoderHelix decoder; // or change to MP3DecoderMAD
|
||||
AudioPlayer player(source, kit, decoder);
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
|
||||
|
||||
// setup output
|
||||
auto cfg = kit.defaultConfig(TX_MODE);
|
||||
cfg.sd_active = false;
|
||||
kit.begin(cfg);
|
||||
|
||||
|
||||
// setup player
|
||||
player.setVolume(0.7);
|
||||
player.begin();
|
||||
|
||||
// select file with setPath() or setIndex()
|
||||
//player.setPath("/ZZ Top/Unknown Album/Lowrider.mp3");
|
||||
//player.setIndex(1); // 2nd file
|
||||
|
||||
}
|
||||
|
||||
void loop() {
|
||||
player.copy();
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,43 @@
|
||||
/**
|
||||
* @file player-spiffs-i2s.ino
|
||||
* @brief example using the SPIFFS library
|
||||
*
|
||||
* @author Phil Schatzmann
|
||||
* @copyright GPLv3
|
||||
*/
|
||||
|
||||
#include "AudioTools.h"
|
||||
#include "AudioTools/Disk/AudioSourceSPIFFS.h"
|
||||
#include "AudioTools/AudioCodecs/CodecMP3Helix.h"
|
||||
|
||||
const char *startFilePath="/";
|
||||
const char* ext="mp3";
|
||||
AudioSourceSPIFFS source(startFilePath, ext);
|
||||
I2SStream i2s;
|
||||
MP3DecoderHelix decoder;
|
||||
AudioPlayer player(source, i2s, decoder);
|
||||
|
||||
void printMetaData(MetaDataType type, const char* str, int len){
|
||||
Serial.print("==> ");
|
||||
Serial.print(toStr(type));
|
||||
Serial.print(": ");
|
||||
Serial.println(str);
|
||||
}
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
|
||||
|
||||
// setup output
|
||||
auto cfg = i2s.defaultConfig(TX_MODE);
|
||||
i2s.begin(cfg);
|
||||
|
||||
// setup player
|
||||
//source.setFileFilter("*Bob Dylan*");
|
||||
player.setMetadataCallback(printMetaData);
|
||||
player.begin();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
player.copy();
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
/**
|
||||
* @file player-vector_sdfat.ino
|
||||
* @brief example that shows how to use the versatile AudioSourceVector class
|
||||
* as data source. We use the SdFat library to read audio files from an SD card.
|
||||
*
|
||||
* @author Phil Schatzmann
|
||||
* @copyright GPLv3
|
||||
*/
|
||||
|
||||
#include "AudioTools.h"
|
||||
#include "AudioTools/AudioCodecs/CodecMP3Helix.h"
|
||||
#include "AudioTools/AudioLibs/AudioBoardStream.h"
|
||||
#include "SPI.h"
|
||||
#include "SdFat.h"
|
||||
|
||||
#define PIN_AUDIO_KIT_SD_CARD_CS 13
|
||||
#define PIN_AUDIO_KIT_SD_CARD_MISO 2
|
||||
#define PIN_AUDIO_KIT_SD_CARD_MOSI 15
|
||||
#define PIN_AUDIO_KIT_SD_CARD_CLK 14
|
||||
|
||||
// Callback to convert file path to stream for AudioSourceVector
|
||||
File32* fileToStream(const char* path, File32& oldFile);
|
||||
|
||||
// Global data
|
||||
AudioSourceVector<File32> source(fileToStream);
|
||||
AudioBoardStream i2s(AudioKitEs8388V1); // or replace with e.g. I2SStream
|
||||
MP3DecoderHelix decoder; // or change to MP3DecoderMAD
|
||||
AudioPlayer player(source, i2s, decoder);
|
||||
SdFat sd;
|
||||
File32 audioFile;
|
||||
|
||||
|
||||
// Callback to convert file path to stream for AudioSourceVector
|
||||
File32* fileToStream(const char* path, File32& oldFile) {
|
||||
oldFile.close();
|
||||
audioFile.open(path);
|
||||
|
||||
if (!audioFile) {
|
||||
LOGE("Failed to open: %s", path);
|
||||
return nullptr;
|
||||
}
|
||||
return &audioFile;
|
||||
}
|
||||
|
||||
bool setupDrive() {
|
||||
// Initialize SD card
|
||||
SPI.begin(PIN_AUDIO_KIT_SD_CARD_CLK, PIN_AUDIO_KIT_SD_CARD_MISO,
|
||||
PIN_AUDIO_KIT_SD_CARD_MOSI, PIN_AUDIO_KIT_SD_CARD_CS);
|
||||
|
||||
if (!sd.begin(PIN_AUDIO_KIT_SD_CARD_CS, SPI_HALF_SPEED)) {
|
||||
Serial.println("SD card initialization failed!");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Use SDFAT's ls method to list files and automatically add file names
|
||||
const char* path = "/Bob Dylan/Bringing It All Back Home";
|
||||
NamePrinter namePrinter(source, path);
|
||||
auto dir = sd.open(path, FILE_READ);
|
||||
dir.ls(&namePrinter, 0);
|
||||
dir.close();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
|
||||
|
||||
// setup vector data source
|
||||
if (!setupDrive()) {
|
||||
Serial.println("Failed to setup drive");
|
||||
stop();
|
||||
}
|
||||
|
||||
// setup output
|
||||
auto cfg = i2s.defaultConfig(TX_MODE);
|
||||
// we setup up the SPI (pins) outselfs...
|
||||
cfg.sd_active = false;
|
||||
if (!i2s.begin(cfg)) {
|
||||
Serial.println("Failed to start I2S");
|
||||
stop();
|
||||
}
|
||||
|
||||
// setup player
|
||||
player.setVolume(0.7);
|
||||
if (!player.begin()) {
|
||||
Serial.println("Failed to start player");
|
||||
stop();
|
||||
}
|
||||
}
|
||||
|
||||
void loop() {
|
||||
player.copy();
|
||||
}
|
||||
Reference in New Issue
Block a user