ESP-IDF Firmware
Firmware architecture and call graph
Loading...
Searching...
No Matches
audio_amp_main.c File Reference
#include <stdio.h>
#include <inttypes.h>
#include <sdkconfig.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "esp_log.h"
#include "esp_dsp.h"
#include "bsp/esp-bsp.h"
#include <stdint.h>
#include <math.h>
Include dependency graph for applications/lyrat_board_app/main/audio_amp_main.c:

Go to the source code of this file.

Macros

#define BUFFER_SIZE   (64)
#define SAMPLE_RATE   (16000)
#define DEFAULT_VOLUME   (100)

Typedefs

typedef enum audio_set audio_set_t

Enumerations

enum  audio_set { AUDIO_VOLUME , AUDIO_BASS , AUDIO_TREBLE }

Functions

static void btn_handler (void *button_handle, void *usr_data)
struct __attribute__ ((packed))
static void buttons_process_task (void *arg)
static void audio_read_task (void *arg)
static void audio_process_task (void *arg)
static void convert_short2float (int16_t *int16_data, float *float_data, int len)
static void convert_float2short (float *float_data, int16_t *int16_data, int len)
void digitalLimiter (float *input_signal, float *output_signal, int signal_length, float threshold, float attack_value, float release_value, float *in_envelope)
void app_main (void)

Variables

static const char * TAG = "example"
static QueueHandle_t audio_button_q = NULL
 dumb_wav_header_t
static esp_codec_dev_handle_t spk_codec_dev = NULL
static FILE * play_file = NULL
static const char play_filename [] = BSP_SPIFFS_MOUNT_POINT"/16bit_mono_44_1_khz.wav"
static dumb_wav_header_t wav_header
static audio_set_t current_set = AUDIO_VOLUME
float iir_coeffs_lpf [5]
float iir_w_lpf [5] = {0, 0}
float iir_coeffs_hpf [5]
float iir_w_hpf [5] = {0, 0}
float lpf_gain = 0
float lpf_qFactor = 0.5
float lpf_freq = 0.01
float hpf_gain = 0
float hpf_qFactor = 1
float hpf_freq = 0.15
float full_volume = 1
int full_volume_db = -12
float full_envelope = 0
float processing_audio_buffer [(64)] = {0}
int16_t triple_audio_buffer [3 *(64)] = {0}
int audio_buffer_write_index = 0
int audio_buffer_read_index = 0
static SemaphoreHandle_t sync_read_task

Macro Definition Documentation

◆ BUFFER_SIZE

◆ DEFAULT_VOLUME

#define DEFAULT_VOLUME   (100)

◆ SAMPLE_RATE

#define SAMPLE_RATE   (16000)

Typedef Documentation

◆ audio_set_t

typedef enum audio_set audio_set_t

Enumeration Type Documentation

◆ audio_set

enum audio_set
Enumerator
AUDIO_VOLUME 
AUDIO_BASS 
AUDIO_TREBLE 

Definition at line 50 of file applications/lyrat_board_app/main/audio_amp_main.c.

Function Documentation

◆ __attribute__()

struct __attribute__ ( (packed) )

Definition at line 31 of file applications/lyrat_board_app/main/audio_amp_main.c.

39{
40 uint8_t ignore_0[22];
41 uint16_t num_channels;
42 uint32_t sample_rate;
43 uint8_t ignore_1[6];
44 uint16_t bits_per_sample;
45 uint8_t ignore_2[4];
46 uint32_t data_size;
47 uint8_t data[];
static float data[128 *2]
Definition test_fft2r.c:34

References audio_button_q, and button_pressed.

◆ app_main()

void app_main ( void )

Definition at line 365 of file applications/lyrat_board_app/main/audio_amp_main.c.

366{
367 ESP_ERROR_CHECK(bsp_spiffs_mount());
368
369 // Create FreeRTOS tasks and queues
370 audio_button_q = xQueueCreate(10, sizeof(int));
371 assert (audio_button_q != NULL);
372
373 BaseType_t ret = xTaskCreate(audio_process_task, "audio_process_task", 4096, NULL, 6, NULL);
374 assert(ret == pdPASS);
375
376 // Init audio buttons
377 button_handle_t btns[BSP_BUTTON_NUM];
378 ESP_ERROR_CHECK(bsp_iot_button_create(btns, NULL, BSP_BUTTON_NUM));
379 for (int i = 0; i < BSP_BUTTON_NUM; i++) {
380 ESP_ERROR_CHECK(iot_button_register_cb(btns[i], BUTTON_PRESS_DOWN, btn_handler, (void *) i));
381 }
382}
static QueueHandle_t audio_button_q
static void btn_handler(void *button_handle, void *usr_data)
static void audio_process_task(void *arg)

References audio_button_q, audio_process_task(), and btn_handler().

Here is the call graph for this function:

◆ audio_process_task()

void audio_process_task ( void * arg)
static

Definition at line 155 of file applications/lyrat_board_app/main/audio_amp_main.c.

156{
157 // Init codeac and apply the initial volume to maximum
158 spk_codec_dev = bsp_audio_codec_speaker_init();
159 assert(spk_codec_dev);
160 esp_codec_dev_set_out_vol(spk_codec_dev, DEFAULT_VOLUME);
161
162 // Open file and het the WAV header to set up the sample frequency, amount of channels and resolution
163 play_file = fopen(play_filename, "rb");
164 if (play_file == NULL) {
165 ESP_LOGW(TAG, "%s file does not exist!", play_filename);
166 }
167 // Read WAV header
168 if (fread((void *)&wav_header, 1, sizeof(wav_header), play_file) != sizeof(wav_header)) {
169 ESP_LOGW(TAG, "Error in reading file");
170 return;
171 }
172
173 ESP_LOGI(TAG, "Number of channels: %" PRIu16 "", wav_header.num_channels);
174 ESP_LOGI(TAG, "Bits per sample: %" PRIu16 "", wav_header.bits_per_sample);
175 ESP_LOGI(TAG, "Sample rate: %" PRIu32 "", wav_header.sample_rate);
176 ESP_LOGI(TAG, "Data size: %" PRIu32 "", wav_header.data_size);
177 esp_codec_dev_sample_info_t fs = {
178 .sample_rate = wav_header.sample_rate,
179 .channel = wav_header.num_channels,
180 .bits_per_sample = wav_header.bits_per_sample,
181 };
182 if (spk_codec_dev != NULL) {
183 int result = esp_codec_dev_open(spk_codec_dev, &fs);
184 }
185 // Calculate initial volume value
186 full_volume = exp10f((float)full_volume_db / 20);
187 // Calculate initial state for LPF
189 // Calculate initial state for HPF
191
192 BaseType_t ret = xTaskCreate(buttons_process_task, "buttons_process_task", 4096, NULL, 4, NULL);
193 assert(ret == pdPASS);
194
195 sync_read_task = xSemaphoreCreateCounting(1, 0);
196
197 ret = xTaskCreate(audio_read_task, "audio_read_task", 4096, NULL, 7, NULL);
198 assert(ret == pdPASS);
199 vTaskDelay(1);
200
201 ESP_LOGW(TAG, "To select volume/bass/treble please use the 'Set' button. And adjust the value with +/- buttons.");
202
203 for (;;) {
204 /* Get data from SPIFFS and send it to codec */
206 // Write samples to audio codec
207 esp_codec_dev_write(spk_codec_dev, wav_bytes, BUFFER_SIZE * sizeof(int16_t));
209 if (audio_buffer_write_index >= 3) {
211 }
212 // Check the triple buffer overflow
214 // Call delay to switch the task to fill the buffer
215 vTaskDelay(1);
216 // Check and indicate overflow status
218 ESP_LOGW(TAG, "Audio buffer overflow!");
219 }
220 }
221 // Generate synt event to read task:
222 xSemaphoreGive(sync_read_task);
223 }
224}
static SemaphoreHandle_t sync_read_task
static void audio_read_task(void *arg)
static const char play_filename[]
static void buttons_process_task(void *arg)
static dumb_wav_header_t wav_header
static esp_codec_dev_handle_t spk_codec_dev
esp_err_t dsps_biquad_gen_lowShelf_f32(float *coeffs, float f, float gain, float qFactor)
low shelf IIR filter coefficients
esp_err_t dsps_biquad_gen_highShelf_f32(float *coeffs, float f, float gain, float qFactor)
high shelf IIR filter coefficients
static const char * TAG
Definition main/main.c:31

References audio_buffer_read_index, audio_buffer_write_index, audio_read_task(), BUFFER_SIZE, buttons_process_task(), DEFAULT_VOLUME, dsps_biquad_gen_highShelf_f32(), dsps_biquad_gen_lowShelf_f32(), full_volume, full_volume_db, hpf_freq, hpf_gain, hpf_qFactor, iir_coeffs_hpf, iir_coeffs_lpf, lpf_freq, lpf_gain, lpf_qFactor, play_file, play_filename, spk_codec_dev, sync_read_task, TAG, triple_audio_buffer, and wav_header.

Referenced by app_main().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ audio_read_task()

void audio_read_task ( void * arg)
static

Definition at line 229 of file applications/lyrat_board_app/main/audio_amp_main.c.

230{
231 while (1) {
232 // Wait the sync semaphore
233 if (xSemaphoreTake(sync_read_task, 100)) {
234 // Get the pointer to the current audio buffer
236 // Read the data from the file
237 uint32_t bytes_read_from_spiffs = fread(wav_buffer, sizeof(int16_t), BUFFER_SIZE, play_file);
238 // Convert input samples from int16 to float for processing
240 // Apply bass
242 // Apply treble
244 // Apply voluve
246 // Apply limiter
248 // Convert from float to int16 for audio codec
250
251 if (bytes_read_from_spiffs != BUFFER_SIZE) {
252 // Rewind the file and read the WAV header
253 rewind(play_file);
254 fread((void *)&wav_header, 1, sizeof(wav_header), play_file);
255 // Read data to the audio buffer
256 bytes_read_from_spiffs = fread(wav_buffer, sizeof(int16_t), BUFFER_SIZE, play_file);
257 }
259 if (audio_buffer_read_index >= 3) {
261 }
262 } else {
263 // Error in case of timeout
264 ESP_LOGE(TAG, "Audio timeout!");
265 }
266 }
267}
void digitalLimiter(float *input_signal, float *output_signal, int signal_length, float threshold, float attack_value, float release_value, float *in_envelope)
static void convert_float2short(float *float_data, int16_t *int16_data, int len)
static void convert_short2float(int16_t *int16_data, float *float_data, int len)
#define dsps_biquad_f32
Definition dsps_biquad.h:99
esp_err_t dsps_mulc_f32_ansi(const float *input, float *output, int len, float C, int step_in, int step_out)
multiply constant

References audio_buffer_read_index, BUFFER_SIZE, convert_float2short(), convert_short2float(), digitalLimiter(), dsps_biquad_f32, dsps_mulc_f32_ansi(), full_envelope, full_volume, iir_coeffs_hpf, iir_coeffs_lpf, iir_w_hpf, iir_w_lpf, play_file, processing_audio_buffer, sync_read_task, TAG, triple_audio_buffer, and wav_header.

Referenced by audio_process_task(), audio_process_task(), and audio_process_task().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ btn_handler()

void btn_handler ( void * button_handle,
void * usr_data )
static

Definition at line 31 of file applications/lyrat_board_app/main/audio_amp_main.c.

32{
33 int button_pressed = (int)usr_data;
34 xQueueSend(audio_button_q, &button_pressed, 0);
35}

Referenced by app_main().

Here is the caller graph for this function:

◆ buttons_process_task()

void buttons_process_task ( void * arg)
static

Definition at line 269 of file applications/lyrat_board_app/main/audio_amp_main.c.

270{
271 while (1) {
272 int btn_index = 0;
273 if (xQueueReceive(audio_button_q, &btn_index, portMAX_DELAY) == pdTRUE) {
274 switch (btn_index) {
275 case BSP_BUTTON_SET: {
276 current_set += 1;
277 if (current_set > 2) {
279 }
280 switch (current_set) {
281 case AUDIO_VOLUME:
282 ESP_LOGW(TAG, "Select volume");
283 break;
284 case AUDIO_BASS:
285 ESP_LOGW(TAG, "Select bass");
286 break;
287 case AUDIO_TREBLE:
288 ESP_LOGW(TAG, "Select treble");
289 break;
290 default:
291 break;
292 }
293 break;
294 }
295 case BSP_BUTTON_VOLDOWN: {
296 switch (current_set) {
297 case AUDIO_VOLUME:
298 full_volume_db -= 3;
299 if (full_volume_db < -36) {
300 full_volume_db = -36;
301 }
302 full_volume = exp10f((float)full_volume_db / 20);
303 ESP_LOGI(TAG, "Volume Down: %i dB", full_volume_db);
304 break;
305 case AUDIO_BASS:
306 lpf_gain -= 1;
307 if (lpf_gain < -12) {
308 lpf_gain = -12;
309 }
310 ESP_LOGI(TAG, "Bass Down: %i", (int)lpf_gain);
312 break;
313 case AUDIO_TREBLE:
314 hpf_gain -= 1;
315 if (hpf_gain < -12) {
316 hpf_gain = -12;
317 }
318 ESP_LOGI(TAG, "Treble Down: %i", (int)hpf_gain);
320 break;
321 default:
322 break;
323 }
324 break;
325 }
326 case BSP_BUTTON_VOLUP: {
327 switch (current_set) {
328 case AUDIO_VOLUME:
329 full_volume_db += 3;
330 if (full_volume_db > 0) {
331 full_volume_db = 0;
332 }
333 full_volume = exp10f((float)full_volume_db / 20);
334 ESP_LOGI(TAG, "Volume Up: %i dB", full_volume_db);
335 break;
336 case AUDIO_BASS:
337 lpf_gain += 1;
338 if (lpf_gain > 12) {
339 lpf_gain = 12;
340 }
341 ESP_LOGI(TAG, "Bass Up: %i", (int)lpf_gain);
343 break;
344 case AUDIO_TREBLE:
345 hpf_gain += 1;
346 if (hpf_gain > 12) {
347 hpf_gain = 12;
348 }
349 ESP_LOGI(TAG, "Treble Up: %i", (int)hpf_gain);
351 break;
352 default:
353 break;
354 }
355 break;
356 }
357 default:
358 ESP_LOGI(TAG, "No function for this button");
359 break;
360 }
361 }
362 }
363}

References AUDIO_BASS, audio_button_q, AUDIO_TREBLE, AUDIO_VOLUME, current_set, dsps_biquad_gen_highShelf_f32(), dsps_biquad_gen_lowShelf_f32(), full_volume, full_volume_db, hpf_freq, hpf_gain, hpf_qFactor, iir_coeffs_hpf, iir_coeffs_lpf, lpf_freq, lpf_gain, lpf_qFactor, and TAG.

Referenced by audio_process_task(), audio_process_task(), and audio_process_task().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ convert_float2short()

void convert_float2short ( float * float_data,
int16_t * int16_data,
int len )
static

Definition at line 119 of file applications/lyrat_board_app/main/audio_amp_main.c.

120{
121 float multiplier = (float)(INT16_MAX + 1);
122 for (int i = 0 ; i < len ; i++) {
123 int16_data[i] = (int16_t)((float)multiplier * (float)float_data[i]);
124 }
125}

Referenced by audio_read_task().

Here is the caller graph for this function:

◆ convert_short2float()

void convert_short2float ( int16_t * int16_data,
float * float_data,
int len )
static

Definition at line 110 of file applications/lyrat_board_app/main/audio_amp_main.c.

111{
112 float multiplier = 1.0 / (float)(INT16_MAX + 1);
113 for (int i = 0 ; i < len ; i++) {
114 float_data[i] = (float)int16_data[i] * multiplier;
115 }
116}

Referenced by audio_read_task().

Here is the caller graph for this function:

◆ digitalLimiter()

void digitalLimiter ( float * input_signal,
float * output_signal,
int signal_length,
float threshold,
float attack_value,
float release_value,
float * in_envelope )

Definition at line 133 of file applications/lyrat_board_app/main/audio_amp_main.c.

134{
135 float envelope = *in_envelope;
136 for (int i = 0; i < signal_length; i++) {
137 // Calculate envelope
138 float abs_input = fabsf(input_signal[i]);
139 if (abs_input > envelope) {
140 envelope = envelope * (1 - attack_value) + attack_value * abs_input;
141 } else {
142 envelope = envelope * (1 - release_value) + release_value * abs_input;
143 }
144
145 // Apply compression
146 if (envelope > threshold) {
147 output_signal[i] = input_signal[i] * (threshold / envelope);
148 } else {
149 output_signal[i] = input_signal[i];
150 }
151 }
152 *in_envelope = envelope;
153}

Referenced by audio_read_task().

Here is the caller graph for this function:

Variable Documentation

◆ audio_buffer_read_index

◆ audio_buffer_write_index

int audio_buffer_write_index = 0

◆ audio_button_q

QueueHandle_t audio_button_q = NULL
static

◆ current_set

◆ dumb_wav_header_t

dumb_wav_header_t

◆ full_envelope

float full_envelope = 0

◆ full_volume

◆ full_volume_db

◆ hpf_freq

◆ hpf_gain

◆ hpf_qFactor

◆ iir_coeffs_hpf

◆ iir_coeffs_lpf

◆ iir_w_hpf

float iir_w_hpf[5] = {0, 0}

◆ iir_w_lpf

float iir_w_lpf[5] = {0, 0}

◆ lpf_freq

◆ lpf_gain

◆ lpf_qFactor

◆ play_file

◆ play_filename

const char play_filename[] = BSP_SPIFFS_MOUNT_POINT"/16bit_mono_44_1_khz.wav"
static

◆ processing_audio_buffer

float processing_audio_buffer[(64)] = {0}

◆ spk_codec_dev

esp_codec_dev_handle_t spk_codec_dev = NULL
static

◆ sync_read_task

◆ TAG

const char* TAG = "example"
static

◆ triple_audio_buffer

int16_t triple_audio_buffer[3 *(64)] = {0}

◆ wav_header