Page 1 of 1

How to control sound volume through software?

Posted: Thu Mar 21, 2019 8:44 am
by __vnv__
Hello everyone,

using example from ESP32 ADF repo (element_sdcard_mp3_example) with UDA1334A [1] I am playing mp3 on my headphones but I cannot control volume. Is there somehow a way to control volume through software?





[1] https://www.google.com/url?sa=i&source= ... 4116035981

Re: How to control sound volume through software?

Posted: Sun Mar 24, 2019 12:26 am
by Superkurt
I also didn't find a solution. Could we use the equalizer features?

https://docs.espressif.com/projects/esp ... lizer.html

Re: How to control sound volume through software?

Posted: Sun Mar 24, 2019 11:40 am
by __vnv__
I have researched through equalizer code but didn't find if this would be possible.
Could someone from ESP32 team answer this please, does such a feature exists?

Re: How to control sound volume through software?

Posted: Fri Mar 29, 2019 9:59 pm
by hallgrim
Hi,

Below is some scraps of code that we use to control the volume in software. Note that this is hardcoded to use 32 bits audio. You can apply the same technique on 16 bits as well, but then you will be loose some dynamic range.

Code: Select all

#include <string.h>
#include <stdint.h>

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"

#include "audio_element.h"
#include "audio_event_iface.h"
#include "audio_mem.h"
#include "audio_common.h"

#define ENVELOPE_FILTER_BUFFER_SIZE (1764)

static esp_err_t envelope_filter_destroy(audio_element_handle_t self) { 
    return ESP_OK; 
}

static esp_err_t envelope_filter_open(audio_element_handle_t self) {
    return ESP_OK;
}

static esp_err_t envelope_filter_close(audio_element_handle_t self) { 
  if (audio_element_get_state(self) != AEL_STATE_PAUSED) {
    audio_element_info_t info = {0};
    audio_element_getinfo(self, &info);
    info.byte_pos = 0;
    audio_element_setinfo(self, &info);
  }
  
  return ESP_OK; 
}

static double currentVolume = 0.2;

void envelope_volume_to(double volume) {
    currentVolume = volume
}

static void apply_envelope(void *buffer, int size) {
  // assume 32 bit samples:
  int32_t *samples = buffer;
  size_t count = size / 4;

  for (size_t i = 0; i < count; i++) {
    samples[i] = samples[i] * currentVolume;
  }
}

static int envelope_filter_process(audio_element_handle_t self, char *buffer, int size)
{
  audio_element_info_t info = { 0 };
  audio_element_getinfo(self, &info);

  int size_read = audio_element_input(self, buffer, size);
  int result = size_read; // Could be negative error code

  if (size_read > 0) {
    apply_envelope(buffer, size_read);
    int size_write = audio_element_output(self, buffer, size_read);
    if (size_write > 0) {
      info.byte_pos += size_write;
    }
    result = size_write;
  }

  audio_element_setinfo(self, &info);
  return result;
}

audio_element_handle_t create_envelope_filter() {
  audio_element_cfg_t cfg = DEFAULT_AUDIO_ELEMENT_CONFIG();

  cfg.process = envelope_filter_process;
  cfg.open = envelope_filter_open;
  cfg.close = envelope_filter_close;
  cfg.destroy = envelope_filter_destroy;

  cfg.buffer_len = ENVELOPE_FILTER_BUFFER_SIZE;

  cfg.tag = "volume";
  cfg.task_prio = 5;
  cfg.task_core = 0;
  cfg.out_rb_size = 3 * ENVELOPE_FILTER_BUFFER_SIZE;
  audio_element_handle_t el = audio_element_init(&cfg);
  mem_assert(el);
  audio_element_info_t info = {0};
  audio_element_setinfo(el, &info);

  return el;
}
To use it you need to create the audio element, register it with the pipeline and link it up.