Audio
Source: src/audio.c · 317 lines · 30 functions.
Module entry points
These functions are exposed to the rest of the project. Open one to follow its decisions and the helpers it calls.
How to read these diagrams
Each function has its own expandable diagram using the actual expressions and statements from this file. Decisions split into True and False; loop bodies are indented. Returns end the function immediately; break and continue follow their C meanings. Arrows between statements show their order when execution reaches them.
These are structural source diagrams before preprocessing, not runtime traces. Conditional compilation and macros remain source expressions. Ternary choices remain inside their statement. Calls are linked separately; callback execution and task scheduling are not inferred.
Functions in this file
clampFrequency() · source line 42
static uint16_t clampFrequency(uint16_t hertz)
- Exit this function
return hertz < 100U ? 100U : hertz > 2000U ? 2000U : hertz;
Read original function source
static uint16_t clampFrequency(uint16_t hertz)
{
return hertz < 100U ? 100U : hertz > 2000U ? 2000U : hertz;
}incrementFor() · source line 47
static uint32_t incrementFor(uint16_t hertz)
- Exit this function
return (uint32_t)(((uint64_t)hertz << 32U) / AUDIO_SAMPLE_RATE);
Read original function source
static uint32_t incrementFor(uint16_t hertz)
{
return (uint32_t)(((uint64_t)hertz << 32U) / AUDIO_SAMPLE_RATE);
}setOutputSampleRate() · source line 52
static esp_err_t setOutputSampleRate(uint32_t sample_rate)
- Execute
i2s_std_clk_config_t clock_config = I2S_STD_CLK_DEFAULT_CONFIG(sample_rate); - Execute
esp_err_t result = i2s_channel_disable(tx_channel); - Decision
result == ESP_OKTrue- Execute
result = i2s_channel_reconfig_std_clock(tx_channel, &clock_config);
FalseContinue after this decision.
- Decision
result == ESP_OKTrue- Execute
result = i2s_channel_enable(tx_channel);
FalseContinue after this decision.
- Exit this function
return result;
Read original function source
static esp_err_t setOutputSampleRate(uint32_t sample_rate)
{
i2s_std_clk_config_t clock_config = I2S_STD_CLK_DEFAULT_CONFIG(sample_rate);
esp_err_t result = i2s_channel_disable(tx_channel);
if (result == ESP_OK) result = i2s_channel_reconfig_std_clock(tx_channel, &clock_config);
if (result == ESP_OK) result = i2s_channel_enable(tx_channel);
return result;
}readLittleEndian16() · source line 61
static uint16_t readLittleEndian16(const uint8_t *data)
- Exit this function
return (uint16_t)data[0] | ((uint16_t)data[1] << 8U);
Read original function source
static uint16_t readLittleEndian16(const uint8_t *data)
{
return (uint16_t)data[0] | ((uint16_t)data[1] << 8U);
}readLittleEndian32() · source line 66
static uint32_t readLittleEndian32(const uint8_t *data)
- Exit this function
return (uint32_t)data[0] | ((uint32_t)data[1] << 8U) | ((uint32_t)data[2] << 16U) | ((uint32_t)data[3] << 24U);
Read original function source
static uint32_t readLittleEndian32(const uint8_t *data)
{
return (uint32_t)data[0] | ((uint32_t)data[1] << 8U) |
((uint32_t)data[2] << 16U) | ((uint32_t)data[3] << 24U);
}openTestWav() · source line 72
static bool openTestWav(FILE **file, size_t *data_bytes)
Calls into this documentation:
- Execute
uint8_t header[12]; - Execute
uint8_t chunk[8]; - Execute
uint8_t format[16]; - Execute
bool have_format = false; - Execute
*file = fopen(TEST_WAV_PATH, "rb"); - Decision
*file == NULL || fread(header, 1U, sizeof(header), *file) != sizeof(header) || memcmp(header, "RIFF", 4U) != 0 || memcmp(&header[8], "WAVE", 4U) != 0True- Decision
*file != NULLTrue- Execute
fclose(*file);
FalseContinue after this decision.
- Execute
*file = NULL; - Exit this function
return false;
FalseContinue after this decision.
- WHILE loop
fread(chunk, 1U, sizeof(chunk), *file) == sizeof(chunk)Repeat body while the loop condition permits; then continue below.
- Execute
const uint32_t chunk_bytes = readLittleEndian32(&chunk[4]); - Decision
memcmp(chunk, "fmt ", 4U) == 0True- Decision
chunk_bytes < sizeof(format) || fread(format, 1U, sizeof(format), *file) != sizeof(format) || readLittleEndian16(&format[0]) != 1U || readLittleEndian16(&format[2]) != 1U || readLittleEndian32(&format[4]) != AUDIO_SAMPLE_RATE || readLittleEndian16(&format[12]) != 2U || readLittleEndian16(&format[14]) != 16U || fseek(*file, (long)(chunk_bytes - sizeof(format) + (chunk_bytes & 1U)), SEEK_CUR) != 0True- Exit enclosing loop or switch
break;
FalseContinue after this decision.
- Execute
have_format = true;
False- Decision
memcmp(chunk, "data", 4U) == 0 && have_format && (chunk_bytes & 1U) == 0UTrue- Execute
*data_bytes = chunk_bytes; - Exit this function
return true;
False- Decision
fseek(*file, (long)(chunk_bytes + (chunk_bytes & 1U)), SEEK_CUR) != 0True- Exit enclosing loop or switch
break;
FalseContinue after this decision.
- Execute
fclose(*file); - Execute
*file = NULL; - Exit this function
return false;
Read original function source
static bool openTestWav(FILE **file, size_t *data_bytes)
{
uint8_t header[12];
uint8_t chunk[8];
uint8_t format[16];
bool have_format = false;
*file = fopen(TEST_WAV_PATH, "rb");
if (*file == NULL || fread(header, 1U, sizeof(header), *file) != sizeof(header) ||
memcmp(header, "RIFF", 4U) != 0 || memcmp(&header[8], "WAVE", 4U) != 0) {
if (*file != NULL) fclose(*file);
*file = NULL;
return false;
}
while (fread(chunk, 1U, sizeof(chunk), *file) == sizeof(chunk)) {
const uint32_t chunk_bytes = readLittleEndian32(&chunk[4]);
if (memcmp(chunk, "fmt ", 4U) == 0) {
if (chunk_bytes < sizeof(format) ||
fread(format, 1U, sizeof(format), *file) != sizeof(format) ||
readLittleEndian16(&format[0]) != 1U || readLittleEndian16(&format[2]) != 1U ||
readLittleEndian32(&format[4]) != AUDIO_SAMPLE_RATE ||
readLittleEndian16(&format[12]) != 2U || readLittleEndian16(&format[14]) != 16U ||
fseek(*file, (long)(chunk_bytes - sizeof(format) + (chunk_bytes & 1U)), SEEK_CUR) != 0) {
break;
}
have_format = true;
} else if (memcmp(chunk, "data", 4U) == 0 && have_format &&
(chunk_bytes & 1U) == 0U) {
*data_bytes = chunk_bytes;
return true;
} else if (fseek(*file, (long)(chunk_bytes + (chunk_bytes & 1U)), SEEK_CUR) != 0) {
break;
}
}
fclose(*file);
*file = NULL;
return false;
}mp3TestTask() · source line 113
static void mp3TestTask(void *argument)
Calls into this documentation:
- Execute
(void)argument; - Execute
FILE *file = fopen(TEST_MP3_PATH, "rb"); - Decision
file == NULL || fseek(file, 0L, SEEK_END) != 0True- Jump to label
goto failed;
FalseContinue after this decision.
- Execute
const long length = ftell(file); - Decision
length <= 0L || fseek(file, 0L, SEEK_SET) != 0True- Jump to label
goto failed;
FalseContinue after this decision.
- Execute
uint8_t *input = malloc((size_t)length); - Decision
input == NULL || fread(input, 1U, (size_t)length, file) != (size_t)lengthTrue- Execute
free(input); - Jump to label
goto failed;
FalseContinue after this decision.
- Execute
fclose(file); - Execute
file = NULL; - Execute
HMP3Decoder decoder = MP3InitDecoder(); - Decision
decoder == NULLTrue- Execute
free(input); - Jump to label
goto failed;
FalseContinue after this decision.
- Execute
test_mp3_error = ESP_OK; - Execute
ESP_LOGI(TAG, "MP3 TEST START: NATIVE MONO STREAM"); - Execute
vTaskDelay(pdMS_TO_TICKS(20U)); - Execute
uint8_t *read_ptr = input; - Execute
int bytes_left = (int)length; - Execute
uint32_t active_rate = 0U; - WHILE loop
test_mp3_enabled && bytes_left > 0Repeat body while the loop condition permits; then continue below.
- Execute
const int offset = MP3FindSyncWord(read_ptr, bytes_left); - Decision
offset < 0True- Exit enclosing loop or switch
break;
FalseContinue after this decision.
- Execute
read_ptr += offset; - Execute
bytes_left -= offset; - Decision
MP3Decode(decoder, &read_ptr, &bytes_left, mp3_output, 0) != 0True- Execute
read_ptr++; - Execute
bytes_left--; - Next loop iteration
continue;
FalseContinue after this decision.
- Execute
MP3FrameInfo info; - Execute
MP3GetLastFrameInfo(decoder, &info); - Decision
info.nChans != 1 || info.bitsPerSample != 16 || info.samprate <= 0True- Execute
test_mp3_error = ESP_ERR_NOT_SUPPORTED; - Exit enclosing loop or switch
break;
FalseContinue after this decision.
- Decision
active_rate != (uint32_t)info.samprateTrue- Decision
setOutputSampleRate((uint32_t)info.samprate) != ESP_OKTrue- Execute
test_mp3_error = ESP_FAIL; - Exit enclosing loop or switch
break;
FalseContinue after this decision.
- Execute
active_rate = (uint32_t)info.samprate;
FalseContinue after this decision.
- Execute
size_t written = 0U; - Decision
i2s_channel_write(tx_channel, mp3_output, (size_t)info.outputSamps * sizeof(mp3_output[0]), &written, portMAX_DELAY) != ESP_OKTrue- Execute
test_mp3_error = ESP_FAIL; - Exit enclosing loop or switch
break;
FalseContinue after this decision.
- Execute
MP3FreeDecoder(decoder); - Execute
free(input); - Execute
(void)setOutputSampleRate(AUDIO_SAMPLE_RATE); - Execute
test_mp3_enabled = false; - Execute
ESP_LOGI(TAG, "MP3 TEST COMPLETE"); - Execute
vTaskDelete(NULL); - Exit this function
return; - Execute
failed: if (file != NULL) fclose(file); - Execute
test_mp3_error = ESP_FAIL; - Execute
test_mp3_enabled = false; - Execute
ESP_LOGE(TAG, "MP3 TEST OPEN OR DECODE FAILED"); - Execute
vTaskDelete(NULL);
Read original function source
static void mp3TestTask(void *argument)
{
(void)argument;
FILE *file = fopen(TEST_MP3_PATH, "rb");
if (file == NULL || fseek(file, 0L, SEEK_END) != 0) goto failed;
const long length = ftell(file);
if (length <= 0L || fseek(file, 0L, SEEK_SET) != 0) goto failed;
uint8_t *input = malloc((size_t)length);
if (input == NULL || fread(input, 1U, (size_t)length, file) != (size_t)length) { free(input); goto failed; }
fclose(file); file = NULL;
HMP3Decoder decoder = MP3InitDecoder();
if (decoder == NULL) { free(input); goto failed; }
test_mp3_error = ESP_OK;
ESP_LOGI(TAG, "MP3 TEST START: NATIVE MONO STREAM");
vTaskDelay(pdMS_TO_TICKS(20U));
uint8_t *read_ptr = input;
int bytes_left = (int)length;
uint32_t active_rate = 0U;
while (test_mp3_enabled && bytes_left > 0) {
const int offset = MP3FindSyncWord(read_ptr, bytes_left);
if (offset < 0) break;
read_ptr += offset; bytes_left -= offset;
if (MP3Decode(decoder, &read_ptr, &bytes_left, mp3_output, 0) != 0) { read_ptr++; bytes_left--; continue; }
MP3FrameInfo info;
MP3GetLastFrameInfo(decoder, &info);
if (info.nChans != 1 || info.bitsPerSample != 16 || info.samprate <= 0) { test_mp3_error = ESP_ERR_NOT_SUPPORTED; break; }
if (active_rate != (uint32_t)info.samprate) {
if (setOutputSampleRate((uint32_t)info.samprate) != ESP_OK) { test_mp3_error = ESP_FAIL; break; }
active_rate = (uint32_t)info.samprate;
}
size_t written = 0U;
if (i2s_channel_write(tx_channel, mp3_output, (size_t)info.outputSamps * sizeof(mp3_output[0]),
&written, portMAX_DELAY) != ESP_OK) { test_mp3_error = ESP_FAIL; break; }
}
MP3FreeDecoder(decoder); free(input);
(void)setOutputSampleRate(AUDIO_SAMPLE_RATE);
test_mp3_enabled = false;
ESP_LOGI(TAG, "MP3 TEST COMPLETE");
vTaskDelete(NULL); return;
failed:
if (file != NULL) fclose(file);
test_mp3_error = ESP_FAIL; test_mp3_enabled = false;
ESP_LOGE(TAG, "MP3 TEST OPEN OR DECODE FAILED");
vTaskDelete(NULL);
}audioTask() · source line 159
static void audioTask(void *argument)
Calls into this documentation:
- Execute
(void)argument; - Execute
int16_t samples[AUDIO_FRAMES]; - Execute
uint32_t phase = 0U; - Execute
FILE *wav_file = NULL; - Execute
size_t wav_bytes_remaining = 0U; - FOR loop
;;Repeat body while the loop condition permits; then continue below.
- Decision
test_mp3_enabledTrue- Execute
vTaskDelay(pdMS_TO_TICKS(10U)); - Next loop iteration
continue;
FalseContinue after this decision.
- Decision
!test_wav_enabled && wav_file != NULLTrue- Execute
fclose(wav_file); - Execute
wav_file = NULL; - Execute
wav_bytes_remaining = 0U; - Execute
ESP_LOGI(TAG, "WAV TEST STOPPED");
FalseContinue after this decision.
- Execute
size_t frame_count = AUDIO_FRAMES; - Decision
test_wav_enabledTrue- Decision
wav_file == NULLTrue- Decision
!openTestWav(&wav_file, &wav_bytes_remaining)True- Execute
test_wav_error = ESP_ERR_INVALID_ARG; - Execute
test_wav_enabled = false; - Execute
ESP_LOGE(TAG, "WAV TEST OPEN OR FORMAT FAILED: %s", TEST_WAV_PATH); - Next loop iteration
continue;
FalseContinue after this decision.
- Execute
test_wav_error = ESP_OK; - Execute
ESP_LOGI(TAG, "WAV TEST START: 22050HZ 16BIT MONO GAIN=%u%%", TEST_WAV_GAIN_PERCENT);
FalseContinue after this decision.
- Execute
frame_count = wav_bytes_remaining / sizeof(samples[0]); - Decision
frame_count > AUDIO_FRAMESTrue- Execute
frame_count = AUDIO_FRAMES;
FalseContinue after this decision.
- Execute
const size_t frames_read = fread(samples, sizeof(samples[0]), frame_count, wav_file); - Execute
wav_bytes_remaining -= frames_read * sizeof(samples[0]); - Execute
const uint8_t volume = master_volume; - FOR loop
size_t frame = 0U; frame < frames_read; ++frameRepeat body while the loop condition permits; then continue below.
- Execute
samples[frame] = (int16_t)(((int32_t)samples[frame] * TEST_WAV_GAIN_PERCENT * volume) / (100U * 100U));
- Execute
frame_count = frames_read; - Decision
frames_read == 0U || wav_bytes_remaining == 0UTrue- Execute
fclose(wav_file); - Execute
wav_file = NULL; - Execute
test_wav_enabled = false; - Execute
ESP_LOGI(TAG, "WAV TEST COMPLETE");
FalseContinue after this decision.
False- Execute
const bool tone_enabled = test_tone_enabled; - Execute
const uint32_t increment = incrementFor(test_tone_frequency); - Execute
const uint8_t volume = master_volume; - FOR loop
size_t frame = 0U; frame < AUDIO_FRAMES; ++frameRepeat body while the loop condition permits; then continue below.
- Execute
int16_t sample = 0; - Decision
tone_enabledTrue- Execute
sample = sine_wave[phase >> 27U]; - Execute
phase += increment; - Execute
sample = (int16_t)(((int32_t)sample * volume) / 100);
FalseContinue after this decision.
- Execute
samples[frame] = sample;
- Decision
frame_count == 0UTrue- Next loop iteration
continue;
FalseContinue after this decision.
- Execute
size_t written = 0U; - Execute
const esp_err_t result = i2s_channel_write(tx_channel, samples, frame_count * sizeof(samples[0]), &written, portMAX_DELAY); - Decision
result != ESP_OKTrue- Execute
last_error = result; - Execute
ESP_LOGE(TAG, "I2S WRITE FAILED: %s", esp_err_to_name(result)); - Execute
vTaskDelay(pdMS_TO_TICKS(20U));
FalseContinue after this decision.
Read original function source
static void audioTask(void *argument)
{
(void)argument;
int16_t samples[AUDIO_FRAMES];
uint32_t phase = 0U;
FILE *wav_file = NULL;
size_t wav_bytes_remaining = 0U;
for (;;) {
if (test_mp3_enabled) { vTaskDelay(pdMS_TO_TICKS(10U)); continue; }
if (!test_wav_enabled && wav_file != NULL) {
fclose(wav_file);
wav_file = NULL;
wav_bytes_remaining = 0U;
ESP_LOGI(TAG, "WAV TEST STOPPED");
}
size_t frame_count = AUDIO_FRAMES;
if (test_wav_enabled) {
if (wav_file == NULL) {
if (!openTestWav(&wav_file, &wav_bytes_remaining)) {
test_wav_error = ESP_ERR_INVALID_ARG;
test_wav_enabled = false;
ESP_LOGE(TAG, "WAV TEST OPEN OR FORMAT FAILED: %s", TEST_WAV_PATH);
continue;
}
test_wav_error = ESP_OK;
ESP_LOGI(TAG, "WAV TEST START: 22050HZ 16BIT MONO GAIN=%u%%", TEST_WAV_GAIN_PERCENT);
}
frame_count = wav_bytes_remaining / sizeof(samples[0]);
if (frame_count > AUDIO_FRAMES) frame_count = AUDIO_FRAMES;
const size_t frames_read = fread(samples, sizeof(samples[0]), frame_count, wav_file);
wav_bytes_remaining -= frames_read * sizeof(samples[0]);
const uint8_t volume = master_volume;
for (size_t frame = 0U; frame < frames_read; ++frame) {
samples[frame] = (int16_t)(((int32_t)samples[frame] * TEST_WAV_GAIN_PERCENT * volume) /
(100U * 100U));
}
frame_count = frames_read;
if (frames_read == 0U || wav_bytes_remaining == 0U) {
fclose(wav_file);
wav_file = NULL;
test_wav_enabled = false;
ESP_LOGI(TAG, "WAV TEST COMPLETE");
}
} else {
const bool tone_enabled = test_tone_enabled;
const uint32_t increment = incrementFor(test_tone_frequency);
const uint8_t volume = master_volume;
for (size_t frame = 0U; frame < AUDIO_FRAMES; ++frame) {
int16_t sample = 0;
if (tone_enabled) {
sample = sine_wave[phase >> 27U];
phase += increment;
sample = (int16_t)(((int32_t)sample * volume) / 100);
}
samples[frame] = sample;
}
}
if (frame_count == 0U) {
continue;
}
size_t written = 0U;
const esp_err_t result = i2s_channel_write(tx_channel, samples,
frame_count * sizeof(samples[0]),
&written, portMAX_DELAY);
if (result != ESP_OK) {
last_error = result;
ESP_LOGE(TAG, "I2S WRITE FAILED: %s", esp_err_to_name(result));
vTaskDelay(pdMS_TO_TICKS(20U));
}
}
}audioInitialize() · source line 231
bool audioInitialize(void)
- Decision
readyTrue- Exit this function
return true;
FalseContinue after this decision.
- Execute
i2s_chan_config_t channel_config = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_1, I2S_ROLE_MASTER); - Execute
channel_config.auto_clear = true; - Execute
esp_err_t result = i2s_new_channel(&channel_config, &tx_channel, NULL); - Decision
result == ESP_OKTrue- Execute
const i2s_std_config_t config = { .clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG(AUDIO_SAMPLE_RATE), .slot_cfg = I2S_STD_PHILIPS_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_MONO), .gpio_cfg = { .mclk = I2S_GPIO_UNUSED, .bclk = AUDIO_BCLK, .ws = AUDIO_LRC, .dout = AUDIO_DIN, .din = I2S_GPIO_UNUSED, .invert_flags = {0}, }, }; - Execute
result = i2s_channel_init_std_mode(tx_channel, &config); - Decision
result == ESP_OKTrue- Execute
result = i2s_channel_enable(tx_channel);
FalseContinue after this decision.
FalseContinue after this decision.
- Decision
result == ESP_OK && xTaskCreate(audioTask, "audio_i2s", 4096U, NULL, 4U, NULL) == pdPASSTrue- Execute
ready = true; - Execute
last_error = ESP_OK; - Execute
ESP_LOGI(TAG, "READY ESP-IDF I2S1 22050HZ 16BIT MONO BCLK=11 LRC=12 DIN=13"); - Exit this function
return true;
FalseContinue after this decision.
- Decision
result == ESP_OKTrue- Execute
result = ESP_ERR_NO_MEM;
FalseContinue after this decision.
- Execute
last_error = result; - Execute
ESP_LOGE(TAG, "INITIALIZE FAILED: %s", esp_err_to_name(result)); - Decision
tx_channel != NULLTrue- Execute
(void)i2s_channel_disable(tx_channel); - Execute
(void)i2s_del_channel(tx_channel); - Execute
tx_channel = NULL;
FalseContinue after this decision.
- Exit this function
return false;
Read original function source
bool audioInitialize(void)
{
if (ready) return true;
i2s_chan_config_t channel_config = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_1, I2S_ROLE_MASTER);
channel_config.auto_clear = true;
esp_err_t result = i2s_new_channel(&channel_config, &tx_channel, NULL);
if (result == ESP_OK) {
const i2s_std_config_t config = {
.clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG(AUDIO_SAMPLE_RATE),
.slot_cfg = I2S_STD_PHILIPS_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_16BIT,
I2S_SLOT_MODE_MONO),
.gpio_cfg = {
.mclk = I2S_GPIO_UNUSED,
.bclk = AUDIO_BCLK,
.ws = AUDIO_LRC,
.dout = AUDIO_DIN,
.din = I2S_GPIO_UNUSED,
.invert_flags = {0},
},
};
result = i2s_channel_init_std_mode(tx_channel, &config);
if (result == ESP_OK) result = i2s_channel_enable(tx_channel);
}
if (result == ESP_OK &&
xTaskCreate(audioTask, "audio_i2s", 4096U, NULL, 4U, NULL) == pdPASS) {
ready = true;
last_error = ESP_OK;
ESP_LOGI(TAG, "READY ESP-IDF I2S1 22050HZ 16BIT MONO BCLK=11 LRC=12 DIN=13");
return true;
}
if (result == ESP_OK) result = ESP_ERR_NO_MEM;
last_error = result;
ESP_LOGE(TAG, "INITIALIZE FAILED: %s", esp_err_to_name(result));
if (tx_channel != NULL) {
(void)i2s_channel_disable(tx_channel);
(void)i2s_del_channel(tx_channel);
tx_channel = NULL;
}
return false;
}audioReady() · source line 272
bool audioReady(void)
- Exit this function
return ready;
Read original function source
bool audioReady(void) { return ready; }audioLastError() · source line 273
int audioLastError(void)
- Exit this function
return last_error;
Read original function source
int audioLastError(void) { return last_error; }audioPlay() · source line 274
void audioPlay(audio_sfx_t effect)
- Execute
(void)effect;
Read original function source
void audioPlay(audio_sfx_t effect) { (void)effect; }audioSetEngineThrust() · source line 275
void audioSetEngineThrust(bool enabled)
- Execute
(void)enabled;
Read original function source
void audioSetEngineThrust(bool enabled) { (void)enabled; }audioSetMasterVolume() · source line 276
void audioSetMasterVolume(uint8_t percent)
- Execute
master_volume = percent > 100U ? 100U : percent;
Read original function source
void audioSetMasterVolume(uint8_t percent) { master_volume = percent > 100U ? 100U : percent; }audioMasterVolume() · source line 277
uint8_t audioMasterVolume(void)
- Exit this function
return master_volume;
Read original function source
uint8_t audioMasterVolume(void) { return master_volume; }audioStartTestTone() · source line 278
void audioStartTestTone(uint16_t hertz)
Calls into this documentation:
- Execute
test_wav_enabled = false; - Execute
test_tone_frequency = clampFrequency(hertz); - Execute
test_tone_enabled = true;
Read original function source
void audioStartTestTone(uint16_t hertz)
{
test_wav_enabled = false;
test_tone_frequency = clampFrequency(hertz);
test_tone_enabled = true;
}audioStopTestTone() · source line 284
void audioStopTestTone(void)
- Execute
test_tone_enabled = false;
Read original function source
void audioStopTestTone(void) { test_tone_enabled = false; }audioSetTestToneFrequency() · source line 285
void audioSetTestToneFrequency(uint16_t hertz)
Calls into this documentation:
- Execute
test_tone_frequency = clampFrequency(hertz);
Read original function source
void audioSetTestToneFrequency(uint16_t hertz) { test_tone_frequency = clampFrequency(hertz); }audioTestToneEnabled() · source line 286
bool audioTestToneEnabled(void)
- Exit this function
return test_tone_enabled;
Read original function source
bool audioTestToneEnabled(void) { return test_tone_enabled; }audioTestToneFrequency() · source line 287
uint16_t audioTestToneFrequency(void)
- Exit this function
return test_tone_frequency;
Read original function source
uint16_t audioTestToneFrequency(void) { return test_tone_frequency; }audioStartTestWav() · source line 288
bool audioStartTestWav(void)
- Decision
!readyTrue- Exit this function
return false;
FalseContinue after this decision.
- Execute
test_tone_enabled = false; - Execute
test_wav_error = ESP_OK; - Execute
test_wav_enabled = true; - Exit this function
return true;
Read original function source
bool audioStartTestWav(void)
{
if (!ready) return false;
test_tone_enabled = false;
test_wav_error = ESP_OK;
test_wav_enabled = true;
return true;
}audioStopTestWav() · source line 296
void audioStopTestWav(void)
- Execute
test_wav_enabled = false;
Read original function source
void audioStopTestWav(void) { test_wav_enabled = false; }audioTestWavEnabled() · source line 297
bool audioTestWavEnabled(void)
- Exit this function
return test_wav_enabled;
Read original function source
bool audioTestWavEnabled(void) { return test_wav_enabled; }audioTestWavError() · source line 298
int audioTestWavError(void)
- Exit this function
return test_wav_error;
Read original function source
int audioTestWavError(void) { return test_wav_error; }audioStartTestMp3() · source line 299
bool audioStartTestMp3(void)
Calls into this documentation:
- Decision
!ready || test_mp3_enabledTrue- Exit this function
return false;
FalseContinue after this decision.
- Execute
audioStopTestTone(); - Execute
audioStopTestWav(); - Execute
test_mp3_error = ESP_OK; - Execute
test_mp3_enabled = true; - Decision
xTaskCreate(mp3TestTask, "mp3_test", 24576U, NULL, 4U, NULL) != pdPASSTrue- Execute
test_mp3_error = ESP_ERR_NO_MEM; - Execute
test_mp3_enabled = false; - Exit this function
return false;
FalseContinue after this decision.
- Exit this function
return true;
Read original function source
bool audioStartTestMp3(void)
{
if (!ready || test_mp3_enabled) return false;
audioStopTestTone(); audioStopTestWav();
test_mp3_error = ESP_OK; test_mp3_enabled = true;
if (xTaskCreate(mp3TestTask, "mp3_test", 24576U, NULL, 4U, NULL) != pdPASS) {
test_mp3_error = ESP_ERR_NO_MEM; test_mp3_enabled = false; return false;
}
return true;
}audioStopTestMp3() · source line 309
void audioStopTestMp3(void)
- Execute
test_mp3_enabled = false;
Read original function source
void audioStopTestMp3(void) { test_mp3_enabled = false; }audioTestMp3Enabled() · source line 310
bool audioTestMp3Enabled(void)
- Exit this function
return test_mp3_enabled;
Read original function source
bool audioTestMp3Enabled(void) { return test_mp3_enabled; }audioTestMp3Error() · source line 311
int audioTestMp3Error(void)
- Exit this function
return test_mp3_error;
Read original function source
int audioTestMp3Error(void) { return test_mp3_error; }audioPlayMusicNote() · source line 312
void audioPlayMusicNote(uint16_t frequency_hz, uint16_t duration_ms)
- Execute
(void)frequency_hz; - Execute
(void)duration_ms;
Read original function source
void audioPlayMusicNote(uint16_t frequency_hz, uint16_t duration_ms)
{
(void)frequency_hz;
(void)duration_ms;
}audioStopMusic() · source line 317
void audioStopMusic(void)
Read original function source
void audioStopMusic(void) {}Complete original file, including constants and data
/* Coded By JD(2026) */
#error "Reference listing only — not provided as build-ready source."
#include "audio.h"
#include "driver/i2s_std.h"
#include "mp3dec.h"
#include "esp_err.h"
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include <stdio.h>
#include <string.h>
#define AUDIO_SAMPLE_RATE 22050U
#define AUDIO_FRAMES 128U
#define AUDIO_BCLK 11
#define AUDIO_LRC 12
#define AUDIO_DIN 13
#define TEST_WAV_PATH "/spiffs/snd/audiocheck.net_sin_740Hz_.wav"
#define TEST_WAV_GAIN_PERCENT 15U
#define TEST_MP3_PATH "/spiffs/snd/othello_back.mp3"
static const char *TAG = "audio";
static const int16_t sine_wave[32] = {
0, 702, 1376, 1998, 2546, 2995, 3326, 3523,
3600, 3523, 3326, 2995, 2546, 1998, 1376, 702,
0, -702, -1376, -1998, -2546, -2995, -3326, -3523,
-3600, -3523, -3326, -2995, -2546, -1998, -1376, -702,
};
static i2s_chan_handle_t tx_channel;
static volatile bool ready;
static volatile bool test_tone_enabled;
static volatile bool test_wav_enabled;
static volatile uint16_t test_tone_frequency = 740U;
static volatile uint8_t master_volume = 100U;
static volatile int last_error;
static volatile int test_wav_error;
static volatile bool test_mp3_enabled;
static volatile int test_mp3_error;
static int16_t mp3_output[2304];
static uint16_t clampFrequency(uint16_t hertz)
{
return hertz < 100U ? 100U : hertz > 2000U ? 2000U : hertz;
}
static uint32_t incrementFor(uint16_t hertz)
{
return (uint32_t)(((uint64_t)hertz << 32U) / AUDIO_SAMPLE_RATE);
}
static esp_err_t setOutputSampleRate(uint32_t sample_rate)
{
i2s_std_clk_config_t clock_config = I2S_STD_CLK_DEFAULT_CONFIG(sample_rate);
esp_err_t result = i2s_channel_disable(tx_channel);
if (result == ESP_OK) result = i2s_channel_reconfig_std_clock(tx_channel, &clock_config);
if (result == ESP_OK) result = i2s_channel_enable(tx_channel);
return result;
}
static uint16_t readLittleEndian16(const uint8_t *data)
{
return (uint16_t)data[0] | ((uint16_t)data[1] << 8U);
}
static uint32_t readLittleEndian32(const uint8_t *data)
{
return (uint32_t)data[0] | ((uint32_t)data[1] << 8U) |
((uint32_t)data[2] << 16U) | ((uint32_t)data[3] << 24U);
}
static bool openTestWav(FILE **file, size_t *data_bytes)
{
uint8_t header[12];
uint8_t chunk[8];
uint8_t format[16];
bool have_format = false;
*file = fopen(TEST_WAV_PATH, "rb");
if (*file == NULL || fread(header, 1U, sizeof(header), *file) != sizeof(header) ||
memcmp(header, "RIFF", 4U) != 0 || memcmp(&header[8], "WAVE", 4U) != 0) {
if (*file != NULL) fclose(*file);
*file = NULL;
return false;
}
while (fread(chunk, 1U, sizeof(chunk), *file) == sizeof(chunk)) {
const uint32_t chunk_bytes = readLittleEndian32(&chunk[4]);
if (memcmp(chunk, "fmt ", 4U) == 0) {
if (chunk_bytes < sizeof(format) ||
fread(format, 1U, sizeof(format), *file) != sizeof(format) ||
readLittleEndian16(&format[0]) != 1U || readLittleEndian16(&format[2]) != 1U ||
readLittleEndian32(&format[4]) != AUDIO_SAMPLE_RATE ||
readLittleEndian16(&format[12]) != 2U || readLittleEndian16(&format[14]) != 16U ||
fseek(*file, (long)(chunk_bytes - sizeof(format) + (chunk_bytes & 1U)), SEEK_CUR) != 0) {
break;
}
have_format = true;
} else if (memcmp(chunk, "data", 4U) == 0 && have_format &&
(chunk_bytes & 1U) == 0U) {
*data_bytes = chunk_bytes;
return true;
} else if (fseek(*file, (long)(chunk_bytes + (chunk_bytes & 1U)), SEEK_CUR) != 0) {
break;
}
}
fclose(*file);
*file = NULL;
return false;
}
static void mp3TestTask(void *argument)
{
(void)argument;
FILE *file = fopen(TEST_MP3_PATH, "rb");
if (file == NULL || fseek(file, 0L, SEEK_END) != 0) goto failed;
const long length = ftell(file);
if (length <= 0L || fseek(file, 0L, SEEK_SET) != 0) goto failed;
uint8_t *input = malloc((size_t)length);
if (input == NULL || fread(input, 1U, (size_t)length, file) != (size_t)length) { free(input); goto failed; }
fclose(file); file = NULL;
HMP3Decoder decoder = MP3InitDecoder();
if (decoder == NULL) { free(input); goto failed; }
test_mp3_error = ESP_OK;
ESP_LOGI(TAG, "MP3 TEST START: NATIVE MONO STREAM");
vTaskDelay(pdMS_TO_TICKS(20U));
uint8_t *read_ptr = input;
int bytes_left = (int)length;
uint32_t active_rate = 0U;
while (test_mp3_enabled && bytes_left > 0) {
const int offset = MP3FindSyncWord(read_ptr, bytes_left);
if (offset < 0) break;
read_ptr += offset; bytes_left -= offset;
if (MP3Decode(decoder, &read_ptr, &bytes_left, mp3_output, 0) != 0) { read_ptr++; bytes_left--; continue; }
MP3FrameInfo info;
MP3GetLastFrameInfo(decoder, &info);
if (info.nChans != 1 || info.bitsPerSample != 16 || info.samprate <= 0) { test_mp3_error = ESP_ERR_NOT_SUPPORTED; break; }
if (active_rate != (uint32_t)info.samprate) {
if (setOutputSampleRate((uint32_t)info.samprate) != ESP_OK) { test_mp3_error = ESP_FAIL; break; }
active_rate = (uint32_t)info.samprate;
}
size_t written = 0U;
if (i2s_channel_write(tx_channel, mp3_output, (size_t)info.outputSamps * sizeof(mp3_output[0]),
&written, portMAX_DELAY) != ESP_OK) { test_mp3_error = ESP_FAIL; break; }
}
MP3FreeDecoder(decoder); free(input);
(void)setOutputSampleRate(AUDIO_SAMPLE_RATE);
test_mp3_enabled = false;
ESP_LOGI(TAG, "MP3 TEST COMPLETE");
vTaskDelete(NULL); return;
failed:
if (file != NULL) fclose(file);
test_mp3_error = ESP_FAIL; test_mp3_enabled = false;
ESP_LOGE(TAG, "MP3 TEST OPEN OR DECODE FAILED");
vTaskDelete(NULL);
}
static void audioTask(void *argument)
{
(void)argument;
int16_t samples[AUDIO_FRAMES];
uint32_t phase = 0U;
FILE *wav_file = NULL;
size_t wav_bytes_remaining = 0U;
for (;;) {
if (test_mp3_enabled) { vTaskDelay(pdMS_TO_TICKS(10U)); continue; }
if (!test_wav_enabled && wav_file != NULL) {
fclose(wav_file);
wav_file = NULL;
wav_bytes_remaining = 0U;
ESP_LOGI(TAG, "WAV TEST STOPPED");
}
size_t frame_count = AUDIO_FRAMES;
if (test_wav_enabled) {
if (wav_file == NULL) {
if (!openTestWav(&wav_file, &wav_bytes_remaining)) {
test_wav_error = ESP_ERR_INVALID_ARG;
test_wav_enabled = false;
ESP_LOGE(TAG, "WAV TEST OPEN OR FORMAT FAILED: %s", TEST_WAV_PATH);
continue;
}
test_wav_error = ESP_OK;
ESP_LOGI(TAG, "WAV TEST START: 22050HZ 16BIT MONO GAIN=%u%%", TEST_WAV_GAIN_PERCENT);
}
frame_count = wav_bytes_remaining / sizeof(samples[0]);
if (frame_count > AUDIO_FRAMES) frame_count = AUDIO_FRAMES;
const size_t frames_read = fread(samples, sizeof(samples[0]), frame_count, wav_file);
wav_bytes_remaining -= frames_read * sizeof(samples[0]);
const uint8_t volume = master_volume;
for (size_t frame = 0U; frame < frames_read; ++frame) {
samples[frame] = (int16_t)(((int32_t)samples[frame] * TEST_WAV_GAIN_PERCENT * volume) /
(100U * 100U));
}
frame_count = frames_read;
if (frames_read == 0U || wav_bytes_remaining == 0U) {
fclose(wav_file);
wav_file = NULL;
test_wav_enabled = false;
ESP_LOGI(TAG, "WAV TEST COMPLETE");
}
} else {
const bool tone_enabled = test_tone_enabled;
const uint32_t increment = incrementFor(test_tone_frequency);
const uint8_t volume = master_volume;
for (size_t frame = 0U; frame < AUDIO_FRAMES; ++frame) {
int16_t sample = 0;
if (tone_enabled) {
sample = sine_wave[phase >> 27U];
phase += increment;
sample = (int16_t)(((int32_t)sample * volume) / 100);
}
samples[frame] = sample;
}
}
if (frame_count == 0U) {
continue;
}
size_t written = 0U;
const esp_err_t result = i2s_channel_write(tx_channel, samples,
frame_count * sizeof(samples[0]),
&written, portMAX_DELAY);
if (result != ESP_OK) {
last_error = result;
ESP_LOGE(TAG, "I2S WRITE FAILED: %s", esp_err_to_name(result));
vTaskDelay(pdMS_TO_TICKS(20U));
}
}
}
bool audioInitialize(void)
{
if (ready) return true;
i2s_chan_config_t channel_config = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_1, I2S_ROLE_MASTER);
channel_config.auto_clear = true;
esp_err_t result = i2s_new_channel(&channel_config, &tx_channel, NULL);
if (result == ESP_OK) {
const i2s_std_config_t config = {
.clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG(AUDIO_SAMPLE_RATE),
.slot_cfg = I2S_STD_PHILIPS_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_16BIT,
I2S_SLOT_MODE_MONO),
.gpio_cfg = {
.mclk = I2S_GPIO_UNUSED,
.bclk = AUDIO_BCLK,
.ws = AUDIO_LRC,
.dout = AUDIO_DIN,
.din = I2S_GPIO_UNUSED,
.invert_flags = {0},
},
};
result = i2s_channel_init_std_mode(tx_channel, &config);
if (result == ESP_OK) result = i2s_channel_enable(tx_channel);
}
if (result == ESP_OK &&
xTaskCreate(audioTask, "audio_i2s", 4096U, NULL, 4U, NULL) == pdPASS) {
ready = true;
last_error = ESP_OK;
ESP_LOGI(TAG, "READY ESP-IDF I2S1 22050HZ 16BIT MONO BCLK=11 LRC=12 DIN=13");
return true;
}
if (result == ESP_OK) result = ESP_ERR_NO_MEM;
last_error = result;
ESP_LOGE(TAG, "INITIALIZE FAILED: %s", esp_err_to_name(result));
if (tx_channel != NULL) {
(void)i2s_channel_disable(tx_channel);
(void)i2s_del_channel(tx_channel);
tx_channel = NULL;
}
return false;
}
bool audioReady(void) { return ready; }
int audioLastError(void) { return last_error; }
void audioPlay(audio_sfx_t effect) { (void)effect; }
void audioSetEngineThrust(bool enabled) { (void)enabled; }
void audioSetMasterVolume(uint8_t percent) { master_volume = percent > 100U ? 100U : percent; }
uint8_t audioMasterVolume(void) { return master_volume; }
void audioStartTestTone(uint16_t hertz)
{
test_wav_enabled = false;
test_tone_frequency = clampFrequency(hertz);
test_tone_enabled = true;
}
void audioStopTestTone(void) { test_tone_enabled = false; }
void audioSetTestToneFrequency(uint16_t hertz) { test_tone_frequency = clampFrequency(hertz); }
bool audioTestToneEnabled(void) { return test_tone_enabled; }
uint16_t audioTestToneFrequency(void) { return test_tone_frequency; }
bool audioStartTestWav(void)
{
if (!ready) return false;
test_tone_enabled = false;
test_wav_error = ESP_OK;
test_wav_enabled = true;
return true;
}
void audioStopTestWav(void) { test_wav_enabled = false; }
bool audioTestWavEnabled(void) { return test_wav_enabled; }
int audioTestWavError(void) { return test_wav_error; }
bool audioStartTestMp3(void)
{
if (!ready || test_mp3_enabled) return false;
audioStopTestTone(); audioStopTestWav();
test_mp3_error = ESP_OK; test_mp3_enabled = true;
if (xTaskCreate(mp3TestTask, "mp3_test", 24576U, NULL, 4U, NULL) != pdPASS) {
test_mp3_error = ESP_ERR_NO_MEM; test_mp3_enabled = false; return false;
}
return true;
}
void audioStopTestMp3(void) { test_mp3_enabled = false; }
bool audioTestMp3Enabled(void) { return test_mp3_enabled; }
int audioTestMp3Error(void) { return test_mp3_error; }
void audioPlayMusicNote(uint16_t frequency_hz, uint16_t duration_ms)
{
(void)frequency_hz;
(void)duration_ms;
}
void audioStopMusic(void) {}