What are WAV’s?
A wav (or more fully wave file) is a simple file format for storing digital sound. It’s little more than the raw numeric data representing the sound wave (hence wave/wav file) with a little bit of header data bolted on at the start to help the program playing the data to know things like: is it stereo or mono, number of bits per sample and number of samples per second. One of the main advantages is that because it’s so simple with no compression most low power CPU’s can decode and play the files easily, even a late 1970’s early 80’s computer would have had little problem from a horsepower point of view. But unfortunately the disadvantage of no compression means that the files tend to be big, in fact huge compared to mp3’s etc. especially when we’re talking of audio that lasts a reasonable time and is not just a very short piece. In this respect those early computers with their limited storage just couldn’t cope. Of course given enough storage, huge files sizes are not a problem if your file fits within your available storage.
Playing back digital sound
So all we need to do is send the numbers representing the sound wave, at a point in time, to a DAC, connect that DAC to an audio amp and then onto a speaker. And that is it. The only thing we need concern ourselves with is how often we send the values to the DAC, this will govern the playback speed. For now I won’t go into detail as I suspect you just want some code to allow you to play wav’s, but suffice to say that this information is stored as a value per second near the start of the wav file and the code just needs to playback at this same rate for perfect sound.
The library
The DACAudio library for the ESP32 that will take care of all the dirty nitty gritty aspects of playing back a wav file and is available for download on this page. The only thing I will say about it is that it is still being actively developed and is far from complete. This shouldn’t affect existing functions for playing WAV’s too much if at all
Sample Code
The library comes with examples, once you’ve installed it go to Files->Examples->XT_Dac_Audio->PlayWav and you should see the code below;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
#include "SoundData.h"; #include "XT_DAC_Audio.h"; XT_Wav_Class ForceWithYou(Force); // create an object of type XT_Wav_Class that is used by // the dac audio class (below), passing wav data as parameter. XT_DAC_Audio_Class DacAudio(25,0); // Create the main player class object. // Use GPIO 25, one of the 2 DAC pins and timer 0 uint32_t DemoCounter=0; // Just a counter to use in the serial monitor // not essential to playing the sound void setup() { Serial.begin(115200); // Not needed for sound, just to demo printing to the serial // Monitor whilst the sound plays, ensure your serial monitor // speed is set to this speed also. } void loop() { DacAudio.FillBuffer(); // Fill the sound buffer with data if(ForceWithYou.Playing==false) // if not playing, DacAudio.Play(&ForceWithYou); // play it, this will cause it to repeat and repeat... Serial.println(DemoCounter++); // Showing that the sound will play as well as your code running here. } |
In addition to this code you should see a second tab called SoundData.h which contains the actual wav sound data that we are going to use. You can ignore this for now. If you look at the code above we create two objects, one called DacAudio that creates an object that will handle any sound production through the DAC. We pass it the DAC GPIO pin and the system timer to use, there are four on the ESP32. We also need an object to hold the wav sound data, this is called ForceWithYou and is of the type XT_Wav_Class. To create this object we pass it the address of the wav sound data.
In the main loop we check if the sound ForceWithYou is playing (and at the first run it won’t be) and if not we play it again so the sound loops again and again and again until you go insane! In addition to demonstrate the way the sound plays independently of your main loop code. The main loop increments an integer and sends it to the serial monitor all the time that the sound is playing. You can see this by opening the serial monitor window.
Adding your own sounds
There are two ways of adding your own sounds, one using a couple of pieces of commonly available software and the other using a single piece of more specific but not widely used software written by someone who uses this library (not myself). The first has the disadvantage that it takes a longer and there are more steps to follow but has the advantage that your anti-virus software will not complain because they are very well known and used by possibly millions of people. The second is much quicker and simpler but as it’s only just been written and not many people have used it your anti-virus will distrust it and stop you using it unless you take steps to allow it. The choice is yours as I’ll explain how to do it both ways.. I
The longer way using Audacity and HxD
For this example I will choose a Star Wars sample from this web page http://www.thesoundarchive.com/star-wars.asp. In particular the clip “The force will be with you always”, the direct link that works at time of writing is http://www.thesoundarchive.com/play-wav-files.asp?sound=starwars/force.wav. Save this file (or whatever file you choose) somewhere on your computer.
Open up the Audacity sound editing software (download from https://www.audacityteam.org/download/). Go to File->Open and open your file. This particular sound file is mono and not stereo so only one track will show (as shown below).
The DacAudio software only works with Mono files (at present, longish time in future before stereo supported) so if you do have two tracks of stereo sound then you can go to “Tracks->Mix->Mix Stereo down to mono” ton mix the tracks down to one single mono track.
Next we need to (usually) reduce the quality to a sample rate lower than 50000Hz (50000 samples per second) as DACAudio can only work with sample rates up to 50Khz. A common high quality setting is 44100Hz. However this will take up a considerable amount of RAM. On the ESP32 this is OK but will take up considerable memory space, so you should aim to reduce it as much as you can whilst still keeping the quality that you require for your particular project. Reducing the sample rate to a much lower value will have little detrimental effect, but it is advised to probably stay above 10Khz but by all means experiment! Different sound samples can be lowered more than others depending on their content. For this file I’m going to reduce it to 10Khz. To do this select all the file (either CTRL-A or “Select->All”) and go to “Tracks->Re-sample”. A window similar to the one below will open:
You can then either choose an option from the drop down menu or type in your own. Click OK. Audacity will take just a second or two to re-sample you file depending upon the size of your original WAV file. Next we also need to set the project to this setting. The “Project Rate” setting is in the bottom left of the Audacity window, here’s a zoomed in image of that area.
Simply type in (or select if it’s one of the pre-set options) your new sample rate.
To save your new file in a format that DACAudio likes go to “File->Save Other->Export as Wav” and the following window will pop up.
The selection menu “Save as Type” must be changed to “Other uncompressed Files”, when you do this some further options will appear underneath this menu.
The “Header” option should be set as “WAV (Microsoft)” and the “Encoding” option as “Unsigned 8-bit PCM”. Click “Save”, you will be prompted with a “Metatags” options window, just leave everything as is and click “OK”. Your sound file is now re-saved at the sample rate you want and in the format DACAudio understands. Next we have to get it into our code. If you look at the supplied example you will see that we have another “Tab” open in the Arduino IDE that has our data in. If you look in this “Tab” you can see that it is a simple byte array. We need to get our raw file data into that format, that’s where HxD comes in…
Making the byte array data
First though before using HxD we need to create a new file to store our data. To create a new TAB in the Arduino IDE go to the far right and you will see this:
Click the small arrow and you will see the following options,
Select the “New Tab” option. It will present a yellow bar towards the bottom of the Arduno IDE with a text box to enter the name of your new file, call it what you like but ensure you end the filename with the “.h” extension showing that this is a header file. Now open HxD (download from https://mh-nexus.de/en/downloads.php?product=HxD) and load up your WAV file (“File->Open”). You will see a load of Hexadecimal data, don’t worry we don’t need to do anything with it, we just need to get HxD to give us this data in a format we can paste into the Arduino IDE. First select all the data (CTRL-A or “Edit->Select All”), then select “Edit->Copy As->C”. You’ve now got the data in a format you can paste into any text editor or in our case the Arduino IDE. Go to the TAB you just created and paste (CTRL-V) into the Arduino editor. You have now got your data into your program and you should be able to play it using the example at the start of this tutorial as a guide.
The quicker way.
At time of writing I’m waiting for approval to link to the software here.