MP3
Introduction
MP3 (MPEG Layer III) is a ubiquitous audio encoding format.
Initially released in 1993 as a way to store compressed audio, it has since spread pretty much everywhere and established itself as one of the most widely used formats to store personal audio.
Offering a decent audio quality to file size ratio, it provides a simple way to store a large collection of music onto relatively small storage devices such as SD cards or other flash-based media.
While there was a time when usage of the format was protected by software licensing, it is now completely free to use since 2017.
The Aecho module
The Aecho module is a complete SPI MP3 player solution based on the famous VS1011 decoder chip from VLSI.
It features a standard 3.5mm stereo audio jack output and allows playing MP3 data with great simplicity.
We provide a library to make it even easier to use. Playing an MP3 file from the VFS requires only a single line of code!
It also allows controlling the output volume from 0 to 256.
This page will present both the wiring of the module as well as how to use the library to get it to play something.
Wiring
The Aecho module needs 4V to 6V input supply. We can share the ioNode's 'VIN' for this since it has the same requirements.
It uses the SPI bus for both control and MP3 streaming. It has two distinct 'CS' (or chip-select) lines for this reason - 'CS' for mp3 data and 'DCS' for control commands.
The module also exposes a 'DREQ' pin which will tell us when the module's internal buffer is ready to receive more MP3 data.
Finally, a 'RESET' signal is also provided to perform a hardware reset of the decoder.
Aecho module pinout
The aecho library handles all of these internally so all we really need to care about is hooking up these lines to some DIO pins on our ioNode.
The animation below shows an example of how to wire the Aecho to an ioNode:
Using the aecho library
In order to use the Aecho we must first add the 'aecho' library to the list of dependencies in our dfe.conf:
# ... deps: - aecho
Using substrate
Let's declare this Aecho module in our substrate (the pin numbers match the example wiring shown above):
# Aecho MP3 module uses :aecho, name: 'audio0', cs_pin: 8, dcs_pin: 9, rst_pin: 10, dreq_pin: 11
This will create an aecho structure pointer 'audio0' (struct aecho *audio0;
) which we can then use to play audio with the methods below:
// Play File uint8_t aecho_play(struct aecho *a, char *file, void (*eof_callback)(void *user), void *user); // Play File - Fixed Length uint8_t aecho_play_n(struct aecho *a, char *file, uint8_t file_len, void (*eof_callback)(void *user), void *user);
When playing a file, we can set a callback function that will be automatically run when the end of file (EOF) is reached. We may also set a user pointer that will be passed to our callback whenever it is run.
1 #include "substrate.h" 2 3 void eof(void *user) 4 { 5 // Reach EOF while playing our file! 6 scli_printf("Reached end of file!\n"); 7 8 // Stop playing 9 aecho_stop(audio0); 10 } 11 12 void init() 13 { 14 // Initialize substrate 15 substrate_init(); 16 17 // Play some file 18 if(aecho_play(audio0, "sdc0p0:/example/music.mp3", eof, 0)) 19 { 20 // Failed to play file :( 21 scli_printf("Failed to play the audio file\n"); 22 } 23 24 // ... 25 }
Manual initialization (without substrate)
For those who prefer to go without the substrate, we can still initialize the Aecho manually. This however will require us to setup the underlying VS1011 decoder as well, and take care of regularly updating the aecho. As always, this is not recommended as it creates unnecessary complexity.
1 #include <vs1011/vs1011.h> 2 #include <aecho/aecho.h> 3 4 // I/O Pins 5 #define PIN_CS 8 6 #define PIN_DCS 9 7 #define PIN_RST 10 8 #define PIN_DREQ 11 9 10 // MP3 Decoder Driver 11 struct vs1011 dec; 12 struct aecho audio0_data; 13 struct aecho *audio0; 14 15 void eof(void *user) 16 { 17 // Reach EOF while playing our file! 18 scli_printf("Reached end of file!\n"); 19 20 // Stop playing 21 aecho_stop(audio0); 22 } 23 24 void main() 25 { 26 // ... 27 28 // Initialize VS1011 Decoder 29 vs1011_init(&dec, PIN_RST, PIN_DREQ, PIN_CS, PIN_DCS); 30 31 // Initialize Aecho module around decoder 32 audio0 = &audio0_data; 33 aecho_init(audio0, &dec); 34 35 // Play some file 36 if(aecho_play(audio0, "sdc0p0:/example/music.mp3", eof, 0)) 37 { 38 // Failed to play file :( 39 scli_printf("Failed to play the audio file\n"); 40 } 41 42 // ... 43 44 // Main Loop 45 for(;;) 46 { 47 // Update decoder 48 aecho_update(audio0); 49 } 50 }
Play control
Some methods are provided to control the playing:
// Pause currently playing file void aecho_pause(struct aecho *a); // Resume playing void aecho_resume(struct aecho *a); // Completely stop playing void aecho_stop(struct aecho *a);
The 'aecho_pause' and 'aecho_resume' methods will maintain the currently playing file handle, while the 'aecho_stop' method will stop playing and release the file handle.
Volume control
A few methods are provided to control the output volume:
// Set Volume void aecho_set_vol(struct aecho *a, uint8_t vol); // Get Volume uint8_t aecho_get_vol(struct aecho *a); // Get Volume as Percentage uint8_t aecho_get_vol_pct(struct aecho *a); // Volume Up void aecho_vol_up(struct aecho *a); // Volume Up - Multiple void aecho_vol_up_x(struct aecho *a, uint8_t x); // Volume Down void aecho_vol_down(struct aecho *a); // Volume Down - Multiple void aecho_vol_down_x(struct aecho *a, uint8_t x);
The volume is an 8-bit unsigned integer from 0 (minimum volume) to AECHO_VOL_MAX (0xfe / 254).