Page 1 of 2

ESP32 audio output

Posted: Wed Nov 22, 2017 1:02 pm
by megabite
Hello,

I'm new on this forum and would like some info on ESP32 boards that I haven't been able to gather conclusively from the specs of most boards.

For an in-car trip computer project, I would like to use an ESP32 board to display (animated) menus on a small TFT screen in the dashboard. Haven't bought one yet though.

Ideally, I would like to be able to play sounds as well, for example when my trip computer shows a "low fuel" or "high oil temperature" warning.

Do ESP32 WROOM boards or similar have the capability to connect a subminiature speaker straight to the board and play sounds? Or what other hardware is needed to make that happen?




Cheers,

megabite

Re: ESP32 audio output

Posted: Thu Nov 23, 2017 9:08 am
by ESP_Sprite
The ESP32 has a built-in 8-bit DAC; if you don't mind the not-really-HiFi quality of that you should be able to get away with an audio amp connected to this. Alternatively, for better sound quality, you can use an external I2S codec and amp.

Re: ESP32 audio output

Posted: Fri Nov 24, 2017 2:31 pm
by megabite
My initial idea was to just have a 0.6'' 0.8W subminiature speaker mounted to it. Which should be fine playing 8-bit sound samples.

Then again, as I've seen on the web, there are I2S amps that can drive a somewhat bigger speaker.

If I connect an amp like this one to my ESP32,

https://www.adafruit.com/product/3006

then what could I drive with it? Could I even hook it up to the car's own sound system speakers, or would that damage the amp as the speakers normally run on 12V coming from the radio?

Re: ESP32 audio output

Posted: Sat Mar 03, 2018 1:18 pm
by megabite
Ok, so I've found some example code that should in theory enable me to output sound via the Adafruit I2S amp. Note that this is for the Arduino IDE:

Code: Select all

#include "driver/i2s.h"
#include "freertos/queue.h"
#include <pgmspace.h>

#include "soundsample.h"


//i2s configuration
int i2s_num = 0; // i2s port number
i2s_config_t i2s_config = {
  .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX),
  .sample_rate = 16000,
  .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
  .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
  .communication_format = (i2s_comm_format_t)(I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB),
  .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, // high interrupt priority
  .dma_buf_count = 8,
  .dma_buf_len = 64   //Interrupt level 1
};

i2s_pin_config_t pin_config = {
  .bck_io_num = 26, //this is BCK pin
  .ws_io_num = 25, // this is LRCK pin
  .data_out_num = 22, // this is DATA output pin
  .data_in_num = -1   //Not used
};


int i2s_write_sample_nb(uint32_t sample) {
  return i2s_write_bytes((i2s_port_t)i2s_num, (const char *)&sample, sizeof(uint32_t), 100);
}

//Main function to play samples from PROGMEM
void playPROGMEMsample(const uint32_t* audioSample) {

  uint32_t sampleSize = sizeof(audioSample) * 4;

  uint32_t counter = 0;
  //initialize i2s with configurations above
  i2s_driver_install((i2s_port_t)i2s_num, &i2s_config, 0, NULL);
  i2s_set_pin((i2s_port_t)i2s_num, &pin_config);
  //set sample rates of i2s to sample rate of wav file
  i2s_set_sample_rates((i2s_port_t)i2s_num, 16000);


  uint32_t readData;

  while (audioSample)  {
    readData = pgm_read_dword(&audioSample[counter++]);
    if (readData == NULL) break;
    i2s_write_sample_nb(readData);
  }

  i2s_driver_uninstall((i2s_port_t)i2s_num); //stop & destroy i2s driver
}

void setup() {

  Serial.begin(115200);
  Serial.println("Serial connection OK");
  playPROGMEMsample(sample1);
}

void loop() {}
Basically, I want the code to read data from PROGMEM and then output it through my I2S amp. The goal of the project is to play all my sound samples from PROGMEM and not have to mess with an SD card, so that part is non-negotiable.

The sound sample is in PROGMEM as a series of hex double words. It's a 16-bit, 16 kHz wav sample, like this:

Code: Select all

const uint32_t sample1[] PROGMEM = {

0xd8040600, 0x37113f27, 0x0b2f343c, 0xfa3efe46, 0xfe3d9531, 0xa8236a05, 0x81f78beb, 0x97e852e6, 
0x03e154e6, 0x8adc57e3, 0x87f29b05, 0xc508e208, 0xa30aae0f, 0xca06e2fb, 0x7becbcdb, 0xb9e1f5d9, 
0x92deb3e7, 0x94f15803, 0x130b58fb, 0x1afe6d03, 0x8f0fa404, 0x73f379f8, 0x82f080eb, 0xbae1e9e9, 
0x5a015e0d, 0xbd07b411, 0x60224c35, 0x9f30ba39, 0x8b4a2a4e, 0x05508851, 0xae39c831, 0x8e2c6520, 
0xc6164910, 0x4d17061c, 0x2c18c514, 0xcb13090d, 0x011cf128, 0xe22c9825, 0x420b76eb, 0xc4e4fbdf, 
0x77d9e6c7, 0x01c9ffd3, 0x7cddbcea, 0xf0f45bfe, 0x31fb1af3, 0x58f358fa, 0x6ffed901, 0x0b040bfe, 
0xe1fbf3ea, 0xbfe080d9, 0x30dcbde0, 0x85d99cd2, 0x3ac608c7, 0x6fd58ef4, 0x9606e90d, 0xd611a61b, 
0xdb30643c, 0x9745a946, 0x1445754d, 0x0149c244, 0x283c823b, 0x1e416b33, 0x942b5220, 0x2117a611, 

// yadayadayada
//yadayadayada...

};
The problem is, I'm not 100 percent sure what I am doing. How do I customize this code so that it will play my sound sample through the Adafruit mono amp? Right now, this code compiles without a problem, but all I get is noise on the speaker that is connected to the Adafruit amp. The amp has its own 3V3 external power supply.

I've attached the Arduino code and the sound sample file.

Re: ESP32 audio output

Posted: Mon Mar 05, 2018 2:27 am
by Archibald
Using I²S should give you really good sound quality so it's probably well worth trying to get it to work. If you find you can't make progress, I suggest you use one of the digital-to-analogue converter (DAC) outputs of the ESP32.

For speech messages, I am using 8-bit samples at 8kHz stored in ESP32 Flash memory. Initially I was concerned that 8-bit may be inadequate. To get maximum dynamic range, I am exporting audio clips from Audacity, having amplified them within Audacity to be on the edge of clipping. The quality is very adequate and certainly would be more than adequate within the noisy environment of a car. By sampling at only 8 kHz, I was concerned that I may need a good low-pass audio filter to cut off signal components above 4kHz. I'm finding the quality of sibilant speech to be questionable but still readily understandable. As I may need to store quite a lot of speech, I would prefer not to increase sampling rate to 16kHz to improve sibilants, but that would be preferable to adding an audio filter.

This makes the software very simple. The output part of my code, using Arduino IDE, is just:

Code: Select all

for (z=0 ; z<size ; z++)
 {
      dac_output_voltage (DAC_CHANNEL_1,buffer[z]);  
      delayMicroseconds(125);        // 8kHz period 
 }
(I'm aware processing time will slightly lower the output sample rate)

For amplification, I purchased from China a very tiny board with the XPT8871 chip and am running it off 5 volt supply. It's output capabilities are similar to your Adafruit board but it works Class AB instead of Class D. The board has quite high amplification so I'm reducing the input signal considerably by a potential divider of 10kΩ and 470Ω (connected to ground). I guess it would go into its overheat protection mode if driven with loud continuous music, but for short speech clips it's fine. My loudspeaker is 65mm which gives good volume but certainly needs to be in a box, or at least mounted on a panel. I am sceptical whether your 0.6" loudspeaker will be adequate.

Re: ESP32 audio output

Posted: Mon Mar 05, 2018 7:53 am
by Archibald
all I get is noise on the speaker that is connected to the Adafruit amp.
For I²S your data needs to be signed in two's complement form. If not you will get extreme distortion that sounds rather like noise.

(If you use one of the ESP32's digital-to-analogue converters, the data needs to be unsigned.)

Re: ESP32 audio output

Posted: Mon Mar 05, 2018 3:51 pm
by megabite
I have sort of half managed to make it work now. It turns out that I had the byte order wrong with my sound sample. It needs to be little endian double words, which it wasn't before.

Now, however, the sample sounds like it's sped up by a few orders of magnitude.

Here's my code:

Code: Select all

#include "driver/i2s.h"
#include "freertos/queue.h"
#include <pgmspace.h>

#include "soundsample.h"


//i2s configuration
int i2s_num = 0; // i2s port number
i2s_config_t i2s_config = {
     .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX),
     .sample_rate = 16000,
     .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
     .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
     .communication_format = (i2s_comm_format_t)(I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB),
     .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, // high interrupt priority
     .dma_buf_count = 8,
     .dma_buf_len = 64   //Interrupt level 1
    };
    
i2s_pin_config_t pin_config = {
    .bck_io_num = 26, //this is BCK pin
    .ws_io_num = 25, // this is LRCK pin
    .data_out_num = 22, // this is DATA output pin
    .data_in_num = -1   //Not used
};

int i2s_write_sample_nb(uint32_t sample) {
  return i2s_write_bytes((i2s_port_t)i2s_num, (const char *)&sample, sizeof(uint32_t), 100);
}

//Main function to play samples from PROGMEM
void playPROGMEMsample(const uint32_t* audioSample) {

 
  uint32_t counter = 0;
  //initialize i2s with configurations above
  i2s_driver_install((i2s_port_t)i2s_num, &i2s_config, 0, NULL);
  i2s_set_pin((i2s_port_t)i2s_num, &pin_config);
  //set sample rates of i2s to sample rate of wav file
  i2s_set_sample_rates((i2s_port_t)i2s_num, 16000);


  uint32_t readData;

  while (audioSample)  {
    readData = pgm_read_dword(&audioSample[counter++]);
    if (readData == NULL) break;
    i2s_write_sample_nb(readData);
  }

  i2s_driver_uninstall((i2s_port_t)i2s_num); //stop & destroy i2s driver
}

void setup() {

  Serial.begin(115200);
  Serial.println("Serial connection OK");
  playPROGMEMsample(sample1);
}

void loop() {


}
How do I slow the playback down?

Re: ESP32 audio output

Posted: Mon Mar 22, 2021 4:17 am
by nobitaemon
how to add volume ?

Re: ESP32 audio output

Posted: Mon Mar 22, 2021 10:24 am
by Archibald
how to add volume ?
Do you wish to make the audio louder or do you wish to have control of the volume?

If you wish to control the volume, do you wish to control it with a knob or digitally such as by using 'up' and 'down' buttons?

Are you using DAC or I²S?

Re: ESP32 audio output

Posted: Tue Mar 30, 2021 2:52 pm
by Stronestert34
I could never thought, but this thread helped me more than anything else with this question.
Thank you, the author.